Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

demo showing how to use deviceorientation apis to create a multi-devi…

…ce 3D explorer
  • Loading branch information...
commit 45f1250a9fce92fbb7e55161567f596271df6979 0 parents
@dontcallmedom authored
1  .gitignore
@@ -0,0 +1 @@
+node_modules
53 app.js
@@ -0,0 +1,53 @@
+var express = require('express');
+var EventEmitter = require('events').EventEmitter;
+var emitter = new EventEmitter();
+var app = express.createServer();
+var fs = require('fs');
+
+var eventQueue = [];
+var queueStart = 0;
+
+app.configure(function(){
+ emitter.setMaxListeners(0);
+ app.use(express.logger());
+ app.set('port', 3000);
+ app.use(express.bodyParser());
+ app.use(express.static(__dirname + '/public', { maxAge: 86400}));
+});
+
+// Run on port 80 when in production mode
+app.configure('production', function(){
+ app.use(express.errorHandler());
+ app.set('port', 80);
+});
+
+
+// rotation
+app.post('/rotate', function(req, res){
+ eventQueue.push({alpha: req.body.alpha, beta: req.body.beta, gamma: req.body.gamma});
+ emitter.emit("rotate", req.body.alpha, req.body.beta, req.body.gamma, eventQueue.length);
+ res.end();
+});
+
+app.get('/', function(req, res) {
+ fs.readFile(__dirname + '/public/index.html', 'utf8', function(err, text){
+ response.send(text);
+ });
+});
+
+// broadcast received draw/clear events
+app.get('/stream', function(req, res) {
+ res.setHeader("Content-Type", 'text/event-stream');
+ res.setHeader("Cache-Control", "no-cache");
+ res.setHeader("Connection", "keep-alive");
+ res.writeHead(200);
+ // avoid timeout
+ setInterval(function() { res.write(":\n"); }, 30000);
+ emitter.on("rotate", function(alpha, beta, gamma, id) {
+ res.write("data: " + JSON.stringify({'alpha': alpha, 'beta': beta, 'gamma': gamma})+ "\n");
+ res.write("id: " + id + "\n\n");
+ });
+});
+
+app.listen(app.set('port'));
+console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
24 public/3D.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+<head><title>3D explorer</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+</head>
+<body>
+<p>This page allows you to explore a 3 dimensional graphics showed on a <a href="html5logo.html">separate page</a>, on a separate screen.</p>
+
+<p id="support">Your device doesn't seem to support the <a href="dev.w3.org/geo/api/spec-source-orientation.html">DeviceOrientation events</a> used by this demonstration.</p>
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
+<script>
+jQuery(document).ready(function ($) {
+if (typeof window.DeviceMotionEvent != undefined) {
+ $("#support").text("Your device can be used for this demonstration: moving your device around will animate the HTML5 logo");
+ window.addEventListener('deviceorientation', function (e) {
+ $.post('/rotate', {"alpha": e.alpha, "beta": e.beta, "gamma": e.gamma});
+ }, false);
+}
+});
+</script>
+
+<address><a href="https://github.com/dontcallmedom/node-3dexplorer">node-3dexplorer on github</a></address>
+</body>
+</html>
15 public/html5logo.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=0;" />
+ <title>The HTML5 logo - K3D demo in HTML5 Canvas and JavaScript </title>
+ <script src="scripts/mathlib-min.js"></script>
+ <script src="scripts/k3d-min.js"></script>
+ </head>
+
+ <body style="margin:0px; overflow:hidden">
+<div id="debug"> </div>
+ <canvas id="canvas" style="background-color:#ddd"></canvas>
+ <script src="scripts/html5logo.js"></script>
+ </body>
+</html>
31 public/index.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html>
+<head><title>3D explorer</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+</head>
+<body>
+<h1>3D Explorer</h1>
+<h2>Introduction</h2>
+
+<p>This demo shows how to use one device (equipped with an accelerometer) to explore in 3 dimensions an object shown on the screen of another device, using only off-the-shelf Web technologies.</p>
+
+<h2>Instructions</h2>
+<ul>
+<li>Load the <a href="html5logo.html">3D object</a> on a given device, typically a regular computer browser</li>
+<li>Load the <a href="3D.html">3D-explorer page</a> on a device with an accelerometer and a browser supporting the accelerometer API (e.g. iPhone &gt; 4, iPad, Firefox on Android, Android browser &gt; 3.0)</li>
+<li>Move the second device and see how the object is animated on the first screen in sync</li>
+</ul>
+
+<h2>Under the hood</h2>
+
+<p>The movements of the second device are captured using <a href="http://dev.w3.org/geo/api/spec-source-orientation.html">W3C DeviceOrientation Events</a>, sent to a proxy server built using <a href="http://nodejs.org/">node.js</a>, and then dispatched to the first device via <a href="http://dev.w3.org/html5/eventsource/">Server-Sent events</a>.</p>
+
+<p>The HTML5 3D logo is built using HTML5’s <a href="http://www.w3.org/TR/2dcontext/"><code>canvas</code></a> element.</p>
+
+<p>The <a href="http://www.kevs3d.co.uk/dev/html5logo/">HTML5 3D logo animation</a> itself comes from <a href="http://www.kevs3d.co.uk/">Kevin Roast’s 3D demos</a>, using the <a href="https://launchpad.net/canvask3d">canvas K3D library</a>.></p>
+
+<p>The code for this demonstration is available on <a href="https://github.com/dontcallmedom/node-3dexplorer">github</a>.</p>
+
+<address><a href="http://www.w3.org/People/Dom/">Dominique Hazael-Massieux</a> (<a href="http://twitter.com/dontcallmedom">@dontcallmedom</a>)</address>
+</body>
+</html>
27 public/license-html5-logo-3d.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2011 Kevin Roast kevtoast@yahoo.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+A "link back" to the original holding website "www.kev3d.co.uk" or a reference
+to the original author "Kevin Roast" shall be provided on any copies or
+substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
219 public/scripts/html5logo.js
@@ -0,0 +1,219 @@
+/**
+ * HTML5 K3D demo
+ *
+ * Copyright (C) Kevin Roast 2010
+ * http://www.kevs3d.co.uk/dev
+ * email: kevtoast at yahoo.com
+ * twitter: @kevinroast
+ *
+ * I place this code in the public domain - because it's not rocket science
+ * and it won't make me any money, so do whatever you want with it, go crazy
+ */
+
+// bind to window onload handler
+window.addEventListener('load', onloadHandler, false);
+var targetAngleX = 0;
+var targetAngleY = 0;
+var targetAngleZ = 0;
+/**
+ * Window onload handler
+ */
+function onloadHandler()
+{
+ var canvas = document.getElementById('canvas');
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ var k3dmain = new K3D.Controller(canvas, true);
+
+ // generate 3D objects
+
+ var obj1 = new K3D.K3DObject();
+ with (obj1)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:-80,y:180,z:0},{x:0,y:180,z:-80},{x:0,y:0,z:-80},{x:-80,y:20,z:0},{x:-50,y:150,z:-30},{x:0,y:150,z:-80},{x:0,y:130,z:-80},{x:-30,y:130,z:-50},{x:-28,y:110,z:-52},{x:0,y:110,z:-80},{x:0,y:90,z:-80},{x:-45,y:90,z:-35},{x:-44,y:80,z:-36},{x:-25,y:80,z:-55},{x:-22,y:66,z:-58},{x:0,y:60,z:-80},{x:0,y:40,z:-80},{x:-40,y:50,z:-40}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[235,235,235],vertices:[4,5,6,7,8,9,10,11,4]},{color:[235,235,235],vertices:[12,13,14,15,16,17,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj1);
+
+ var obj2 = new K3D.K3DObject();
+ with (obj2)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:0,y:180,z:-80},{x:80,y:180,z:0},{x:80,y:20,z:0},{x:0,y:0,z:-80},{x:0,y:165,z:-80},{x:68,y:165,z:-12},{x:55,y:35,z:-25},{x:0,y:20,z:-80},{x:0,y:150,z:-80},{x:50,y:150,z:-30},{x:47,y:130,z:-33},{x:0,y:130,z:-80},{x:0,y:110,z:-80},{x:45,y:110,z:-35},{x:40,y:50,z:-40},{x:0,y:40,z:-80},{x:0,y:60,z:-80},{x:20,y:66,z:-60},{x:23,y:90,z:-57},{x:0,y:90,z:-80}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[240,101,41],vertices:[4,5,6,7,4]},{color:[235,235,235],vertices:[8,9,10,11,8]},{color:[235,235,235],vertices:[12,13,14,15,16,17,18,19,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj2);
+
+ var obj3 = new K3D.K3DObject();
+ with (obj3)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:80,y:180,z:0},{x:0,y:180,z:80},{x:0,y:0,z:80},{x:80,y:20,z:0},{x:50,y:150,z:30},{x:0,y:150,z:80},{x:0,y:130,z:80},{x:30,y:130,z:50},{x:28,y:110,z:52},{x:0,y:110,z:80},{x:0,y:90,z:80},{x:45,y:90,z:35},{x:44,y:80,z:36},{x:25,y:80,z:55},{x:22,y:66,z:58},{x:0,y:60,z:80},{x:0,y:40,z:80},{x:40,y:50,z:40}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[235,235,235],vertices:[4,5,6,7,8,9,10,11,4]},{color:[235,235,235],vertices:[12,13,14,15,16,17,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj3);
+
+ var obj4 = new K3D.K3DObject();
+ with (obj4)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:0,y:180,z:80},{x:-80,y:180,z:0},{x:-80,y:20,z:0},{x:0,y:0,z:80},{x:0,y:165,z:80},{x:-68,y:165,z:12},{x:-55,y:35,z:25},{x:0,y:20,z:80},{x:0,y:150,z:80},{x:-50,y:150,z:30},{x:-47,y:130,z:33},{x:0,y:130,z:80},{x:0,y:110,z:80},{x:-45,y:110,z:35},{x:-40,y:50,z:40},{x:0,y:40,z:80},{x:0,y:60,z:80},{x:-20,y:66,z:60},{x:-23,y:90,z:57},{x:0,y:90,z:80}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[240,101,41],vertices:[4,5,6,7,4]},{color:[235,235,235],vertices:[8,9,10,11,8]},{color:[235,235,235],vertices:[12,13,14,15,16,17,18,19,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj4);
+
+ var objBase = new K3D.K3DObject();
+ with (objBase)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:0,y:0,z:-80},{x:-80,y:20,z:0},{x:0,y:0,z:80},{x:80,y:20,z:0}],
+ [],
+ [{color:[227,76,38],vertices:[0,2,1,0]},{color:[227,76,38],vertices:[0,3,2,0]}]
+ );
+ }
+ k3dmain.addK3DObject(objBase);
+
+ var objHtml = new K3D.K3DObject();
+ with (objHtml)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ //sortmode = "unsorted";
+ color = [64,64,64];
+ doublesided = true;
+ addphi = -0;
+ abouty = 100;
+ scale = 0.75;
+ perslevel = 1000;
+ init(
+ [{x:-80,y:40,z:0},{x:-70,y:40,z:0},{x:-70,y:30,z:0},{x:-60,y:30,z:0},{x:-60,y:40,z:0},{x:-50,y:40,z:0},{x:-50,y:10,z:0},{x:-60,y:10,z:0},{x:-60,y:20,z:0},{x:-70,y:20,z:0},{x:-70,y:10,z:0},{x:-80,y:10,z:0},{x:-40,y:40,z:0},{x:-10,y:40,z:0},{x:-10,y:30,z:0},{x:-20,y:30,z:0},{x:-20,y:10,z:0},{x:-30,y:10,z:0},{x:-30,y:30,z:0},{x:-40,y:30,z:0},{x:0,y:40,z:0},{x:10,y:40,z:0},{x:20,y:30,z:0},{x:30,y:40,z:0},{x:40,y:40,z:0},{x:40,y:10,z:0},{x:30,y:10,z:0},{x:30,y:30,z:0},{x:20,y:20,z:0},{x:10,y:30,z:0},{x:10,y:10,z:0},{x:0,y:10,z:0},{x:50,y:40,z:0},{x:60,y:40,z:0},{x:60,y:20,z:0},{x:80,y:20,z:0},{x:80,y:10,z:0},{x:50,y:10,z:0}],
+ [],
+ [{vertices:[0,1,2,3,4,5,6,7,8,9,10,11,0]},{vertices:[12,13,14,15,16,17,18,19,12]},{vertices:[20,21,22,23,24,25,26,27,28,29,30,31,20]},{vertices:[32,33,34,35,36,37,32]}]
+ );
+ }
+ k3dmain.addK3DObject(objHtml);
+
+ // add render loop callback
+ var ctx = canvas.getContext('2d');
+ var rotationOffset = 0;
+ var len = (canvas.height > canvas.width ? canvas.height : canvas.width) * 0.7;
+ k3dmain.clearBackground = false;
+ k3dmain.callback = function()
+ {
+ // manually clear bg - as we want to render some extra goodies
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ // draw bg effect before K3D does its 3D rendering
+ ctx.save();
+ ctx.translate(canvas.width/2, canvas.height/2);
+// ctx.rotate(rotationOffset);
+
+ var RAYCOUNT = 32;
+ for (var j=0; j<RAYCOUNT; j++)
+ {
+ // rotate context
+ ctx.rotate(TWOPI / RAYCOUNT);
+ ctx.fillStyle = "#ddd";
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(-16, len);
+ ctx.lineTo(-12, len);
+ ctx.closePath();
+ ctx.fill();
+ ctx.fillStyle = "#fff";
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(-12, len);
+ ctx.lineTo(12, len);
+ ctx.closePath();
+ ctx.fill();
+ ctx.fillStyle = "#ddd";
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(12, len);
+ ctx.lineTo(16, len);
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+ // apply user interaction to rotation
+ for (var i=0, objs=k3dmain.objects; i<objs.length; i++)
+ {
+ objs[i].ophi = targetAngleX;
+ objs[i].otheta = targetAngleY;
+ objs[i].ogamma = targetAngleZ;
+ }
+
+/* if (targetRotationX > -0.5) targetRotationX -= 0.05;
+ else if (targetRotationX < -0.55) targetRotationX += 0.05;
+ if (targetRotationX > -0.55 && targetRotationX < -0.5) targetRotationX = -0.5;*/
+ };
+
+ // start demo loop
+ k3dmain.paused = true;
+ setInterval(function(){k3dmain.tick();}, 1000/60);
+}
+
+var startAngleX;
+var startAngleY;
+var startAngleZ;
+
+
+var dbg = document.getElementById("debug");
+function debug(text) {
+ var txt = document.createTextNode(text);
+ dbg.replaceChild(txt, dbg.childNodes[0]);
+}
+var eventsource = new EventSource("/stream");
+eventsource.onmessage = function(e) {
+ var data = JSON.parse(e.data);
+ if (!startAngleX) {
+ startAngleX = -data.alpha;
+ startAngleY = -data.gamma;
+ startAngleZ = data.beta;
+ }
+ debug("X: " + data.alpha + ", Y: " + data.gamma + ", Z:" + data.beta);
+ targetAngleX = -data.alpha - startAngleX;
+ targetAngleY = -data.gamma - startAngleY;
+ targetAngleZ = data.beta - startAngleZ;
+ debug("X: " + targetAngleX + ", Y: " + targetAngleY + ", Z:" + targetAngleZ);
+};
271 public/scripts/html5logo.js~
@@ -0,0 +1,271 @@
+/**
+ * HTML5 K3D demo
+ *
+ * Copyright (C) Kevin Roast 2010
+ * http://www.kevs3d.co.uk/dev
+ * email: kevtoast at yahoo.com
+ * twitter: @kevinroast
+ *
+ * I place this code in the public domain - because it's not rocket science
+ * and it won't make me any money, so do whatever you want with it, go crazy
+ */
+
+// bind to window onload handler
+window.addEventListener('load', onloadHandler, false);
+
+/**
+ * Window onload handler
+ */
+function onloadHandler()
+{
+ var canvas = document.getElementById('canvas');
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ var k3dmain = new K3D.Controller(canvas, true);
+
+ // generate 3D objects
+
+ var obj1 = new K3D.K3DObject();
+ with (obj1)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0.5;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:-80,y:180,z:0},{x:0,y:180,z:-80},{x:0,y:0,z:-80},{x:-80,y:20,z:0},{x:-50,y:150,z:-30},{x:0,y:150,z:-80},{x:0,y:130,z:-80},{x:-30,y:130,z:-50},{x:-28,y:110,z:-52},{x:0,y:110,z:-80},{x:0,y:90,z:-80},{x:-45,y:90,z:-35},{x:-44,y:80,z:-36},{x:-25,y:80,z:-55},{x:-22,y:66,z:-58},{x:0,y:60,z:-80},{x:0,y:40,z:-80},{x:-40,y:50,z:-40}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[235,235,235],vertices:[4,5,6,7,8,9,10,11,4]},{color:[235,235,235],vertices:[12,13,14,15,16,17,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj1);
+
+ var obj2 = new K3D.K3DObject();
+ with (obj2)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0.5;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:0,y:180,z:-80},{x:80,y:180,z:0},{x:80,y:20,z:0},{x:0,y:0,z:-80},{x:0,y:165,z:-80},{x:68,y:165,z:-12},{x:55,y:35,z:-25},{x:0,y:20,z:-80},{x:0,y:150,z:-80},{x:50,y:150,z:-30},{x:47,y:130,z:-33},{x:0,y:130,z:-80},{x:0,y:110,z:-80},{x:45,y:110,z:-35},{x:40,y:50,z:-40},{x:0,y:40,z:-80},{x:0,y:60,z:-80},{x:20,y:66,z:-60},{x:23,y:90,z:-57},{x:0,y:90,z:-80}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[240,101,41],vertices:[4,5,6,7,4]},{color:[235,235,235],vertices:[8,9,10,11,8]},{color:[235,235,235],vertices:[12,13,14,15,16,17,18,19,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj2);
+
+ var obj3 = new K3D.K3DObject();
+ with (obj3)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0.5;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:80,y:180,z:0},{x:0,y:180,z:80},{x:0,y:0,z:80},{x:80,y:20,z:0},{x:50,y:150,z:30},{x:0,y:150,z:80},{x:0,y:130,z:80},{x:30,y:130,z:50},{x:28,y:110,z:52},{x:0,y:110,z:80},{x:0,y:90,z:80},{x:45,y:90,z:35},{x:44,y:80,z:36},{x:25,y:80,z:55},{x:22,y:66,z:58},{x:0,y:60,z:80},{x:0,y:40,z:80},{x:40,y:50,z:40}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[235,235,235],vertices:[4,5,6,7,8,9,10,11,4]},{color:[235,235,235],vertices:[12,13,14,15,16,17,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj3);
+
+ var obj4 = new K3D.K3DObject();
+ with (obj4)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0.5;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:0,y:180,z:80},{x:-80,y:180,z:0},{x:-80,y:20,z:0},{x:0,y:0,z:80},{x:0,y:165,z:80},{x:-68,y:165,z:12},{x:-55,y:35,z:25},{x:0,y:20,z:80},{x:0,y:150,z:80},{x:-50,y:150,z:30},{x:-47,y:130,z:33},{x:0,y:130,z:80},{x:0,y:110,z:80},{x:-45,y:110,z:35},{x:-40,y:50,z:40},{x:0,y:40,z:80},{x:0,y:60,z:80},{x:-20,y:66,z:60},{x:-23,y:90,z:57},{x:0,y:90,z:80}],
+ [],
+ [{color:[227,76,38],vertices:[0,1,2,3,0]},{color:[240,101,41],vertices:[4,5,6,7,4]},{color:[235,235,235],vertices:[8,9,10,11,8]},{color:[235,235,235],vertices:[12,13,14,15,16,17,18,19,12]}]
+ );
+ }
+ k3dmain.addK3DObject(obj4);
+
+ var objBase = new K3D.K3DObject();
+ with (objBase)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ sortmode = "unsorted";
+ addphi = -0.5;
+ abouty = -90;
+ perslevel = 1000;
+ init(
+ [{x:0,y:0,z:-80},{x:-80,y:20,z:0},{x:0,y:0,z:80},{x:80,y:20,z:0}],
+ [],
+ [{color:[227,76,38],vertices:[0,2,1,0]},{color:[227,76,38],vertices:[0,3,2,0]}]
+ );
+ }
+ k3dmain.addK3DObject(objBase);
+
+ var objHtml = new K3D.K3DObject();
+ with (objHtml)
+ {
+ drawmode = "solid";
+ shademode = "lightsource";
+ //sortmode = "unsorted";
+ color = [64,64,64];
+ doublesided = true;
+ addphi = -0.5;
+ abouty = 100;
+ scale = 0.75;
+ perslevel = 1000;
+ init(
+ [{x:-80,y:40,z:0},{x:-70,y:40,z:0},{x:-70,y:30,z:0},{x:-60,y:30,z:0},{x:-60,y:40,z:0},{x:-50,y:40,z:0},{x:-50,y:10,z:0},{x:-60,y:10,z:0},{x:-60,y:20,z:0},{x:-70,y:20,z:0},{x:-70,y:10,z:0},{x:-80,y:10,z:0},{x:-40,y:40,z:0},{x:-10,y:40,z:0},{x:-10,y:30,z:0},{x:-20,y:30,z:0},{x:-20,y:10,z:0},{x:-30,y:10,z:0},{x:-30,y:30,z:0},{x:-40,y:30,z:0},{x:0,y:40,z:0},{x:10,y:40,z:0},{x:20,y:30,z:0},{x:30,y:40,z:0},{x:40,y:40,z:0},{x:40,y:10,z:0},{x:30,y:10,z:0},{x:30,y:30,z:0},{x:20,y:20,z:0},{x:10,y:30,z:0},{x:10,y:10,z:0},{x:0,y:10,z:0},{x:50,y:40,z:0},{x:60,y:40,z:0},{x:60,y:20,z:0},{x:80,y:20,z:0},{x:80,y:10,z:0},{x:50,y:10,z:0}],
+ [],
+ [{vertices:[0,1,2,3,4,5,6,7,8,9,10,11,0]},{vertices:[12,13,14,15,16,17,18,19,12]},{vertices:[20,21,22,23,24,25,26,27,28,29,30,31,20]},{vertices:[32,33,34,35,36,37,32]}]
+ );
+ }
+ k3dmain.addK3DObject(objHtml);
+
+ // add render loop callback
+ var ctx = canvas.getContext('2d');
+ var rotationOffset = 0;
+ var len = (canvas.height > canvas.width ? canvas.height : canvas.width) * 0.7;
+ k3dmain.clearBackground = false;
+ k3dmain.callback = function()
+ {
+ // manually clear bg - as we want to render some extra goodies
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ // draw bg effect before K3D does its 3D rendering
+ ctx.save();
+ ctx.translate(canvas.width/2, canvas.height/2);
+ ctx.rotate(rotationOffset);
+
+ var RAYCOUNT = 32;
+ for (var i=0; i<RAYCOUNT; i++)
+ {
+ // rotate context
+ ctx.rotate(TWOPI / RAYCOUNT);
+ ctx.fillStyle = "#ddd";
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(-16, len);
+ ctx.lineTo(-12, len);
+ ctx.closePath();
+ ctx.fill();
+ ctx.fillStyle = "#fff";
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(-12, len);
+ ctx.lineTo(12, len);
+ ctx.closePath();
+ ctx.fill();
+ ctx.fillStyle = "#ddd";
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(12, len);
+ ctx.lineTo(16, len);
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+ rotationOffset += 0.005;
+
+ // apply user interaction to rotation
+ for (var i=0, objs=k3dmain.objects; i<objs.length; i++)
+ {
+ objs[i].ophi += targetRotationX;
+ }
+
+ if (targetRotationX > -0.5) targetRotationX -= 0.05;
+ else if (targetRotationX < -0.55) targetRotationX += 0.05;
+ if (targetRotationX > -0.55 && targetRotationX < -0.5) targetRotationX = -0.5;
+ };
+
+ // start demo loop
+ k3dmain.paused = true;
+ setInterval(function(){k3dmain.tick()}, 1000/60);
+}
+
+// nifty drag/touch event capture code borrowed from Mr Doob http://mrdoob.com/
+var targetRotationX = 0;
+var targetRotationOnMouseDownX = 0;
+var mouseX = 0;
+var mouseXOnMouseDown = 0;
+var targetRotationY = 0;
+var targetRotationOnMouseDownY = 0;
+var mouseY = 0;
+var mouseYOnMouseDown = 0;
+
+var windowHalfX = window.innerWidth / 2;
+var windowHalfY = window.innerHeight / 2;
+
+document.addEventListener('mousedown', onDocumentMouseDown, false);
+document.addEventListener('touchstart', onDocumentTouchStart, false);
+document.addEventListener('touchmove', onDocumentTouchMove, false);
+
+function onDocumentMouseDown( event ) {
+
+ event.preventDefault();
+
+ document.addEventListener('mousemove', onDocumentMouseMove, false);
+ document.addEventListener('mouseup', onDocumentMouseUp, false);
+ document.addEventListener('mouseout', onDocumentMouseOut, false);
+
+ mouseXOnMouseDown = event.clientX - windowHalfX;
+ targetRotationOnMouseDownX = targetRotationX;
+ mouseYOnMouseDown = event.clientY - windowHalfY;
+ targetRotationOnMouseDownY = targetRotationY;
+}
+
+function onDocumentMouseMove( event )
+{
+ mouseX = event.clientX - windowHalfX;
+ targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.02;
+ mouseY = event.clientY - windowHalfY;
+ targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.02;
+}
+
+function onDocumentMouseUp( event )
+{
+ document.removeEventListener('mousemove', onDocumentMouseMove, false);
+ document.removeEventListener('mouseup', onDocumentMouseUp, false);
+ document.removeEventListener('mouseout', onDocumentMouseOut, false);
+}
+
+function onDocumentMouseOut( event )
+{
+ document.removeEventListener('mousemove', onDocumentMouseMove, false);
+ document.removeEventListener('mouseup', onDocumentMouseUp, false);
+ document.removeEventListener('mouseout', onDocumentMouseOut, false);
+}
+
+function onDocumentTouchStart( event )
+{
+ if (event.touches.length == 1)
+ {
+ event.preventDefault();
+
+ mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
+ targetRotationOnMouseDownX = targetRotationX;
+ mouseYOnMouseDown = event.touches[0].pageY - windowHalfY;
+ targetRotationOnMouseDownY = targetRotationY;
+ }
+}
+
+function onDocumentTouchMove( event )
+{
+ if (event.touches.length == 1)
+ {
+ event.preventDefault();
+
+ mouseX = event.touches[0].pageX - windowHalfX;
+ targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.05;
+ mouseY = event.touches[0].pageY - windowHalfY;
+ targetRotationY = targetRotationOnMouseDownY + (mouseX - mouseYOnMouseDown) * 0.05;
+ }
+}
1  public/scripts/k3d-min.js
@@ -0,0 +1 @@
+var DEBUG={};if(typeof K3D=="undefined"||!K3D){var K3D={}}(function(){K3D.BaseController=function(){this.objects=[];this.lights=[];this.renderers=[];this.renderers.point=new K3D.PointRenderer();this.renderers.wireframe=new K3D.WireframeRenderer();this.renderers.solid=new K3D.SolidRenderer()};K3D.BaseController.prototype={renderers:null,objects:null,lights:null,sort:true,addK3DObject:function(a){a.setController(this);this.objects.push(a)},addLightSource:function(a){this.lights.push(a)},getRenderer:function(a){return this.renderers[a]},processFrame:function(c){var g=this.objects;for(var f=0,a=g.length;f<a;f++){g[f].executePipeline()}var e=this.lights;for(var f=0,a=e.length;f<a;f++){e[f].executePipeline()}if(this.sort){g.forEach(function b(k,j,h){k.averagez=null});g.sort(function d(i,h){if(i.averagez===null){i.calculateAverageZ()}if(h.averagez===null){h.calculateAverageZ()}return(i.averagez<h.averagez?1:-1)})}for(var f=0,a=g.length;f<a;f++){c.save();g[f].executeRenderer(c);c.restore()}}}})();(function(){K3D.Controller=function(b,a){K3D.Controller.superclass.constructor.call(this);this.canvas=b;var c=this;if(!a){b.onclick=function(d){c.paused=!c.paused;if(!c.paused){c.frame()}}}};extend(K3D.Controller,K3D.BaseController,{canvas:null,clearBackground:true,fillStyle:null,paused:true,callback:null,fps:40,lastFrameStart:0,addK3DObject:function(a){a.setController(this,this.canvas.width,this.canvas.height);this.objects.push(a)},tick:function(){this.frame()},frame:function(){var f=new Date().getTime();if(this.callback){this.callback.call(this)}var a=this.canvas.getContext("2d");if(this.clearBackground){if(this.fillStyle!==null){a.fillStyle=this.fillStyle;a.fillRect(0,0,this.canvas.width,this.canvas.height)}else{a.clearRect(0,0,this.canvas.width,this.canvas.height)}}this.processFrame(a);var b=1000/this.fps;var e=(new Date().getTime()-f);if(!this.paused){var d=this;setTimeout(function(){d.frame()},b-e<=0?1:b-e)}if(DEBUG&&DEBUG.FPS){a.fillStyle="grey";a.fillText("TPF: "+e,4,48);var c=Math.round(1000/(f-this.lastFrameStart));a.fillText("FPS: "+c,4,64)}this.lastFrameStart=f}})})();(function(){K3D.BaseObject=function(){this.matrix=new Array(3);for(var a=0;a<3;a++){this.matrix[a]=new Array(3)}this.angles=new Array(6);return this};K3D.BaseObject.prototype={matrix:null,angles:null,offx:0,offy:0,offz:0,aboutx:0,abouty:0,aboutz:0,ogamma:0,otheta:0,ophi:0,addgamma:0,addtheta:0,addphi:0,velx:0,vely:0,velz:0,bminx:0,bminy:0,bminz:0,bmaxx:0,bmaxy:0,bmaxz:0,doublesided:false,calcMatrix:function(){var b=this.angles,a=this.matrix;b[0]=Sin(this.ogamma*RAD);b[1]=Cos(this.ogamma*RAD);b[2]=Sin(this.otheta*RAD);b[3]=Cos(this.otheta*RAD);b[4]=Sin(this.ophi*RAD);b[5]=Cos(this.ophi*RAD);a[0][0]=b[5]*b[1];a[1][0]=-(b[5]*b[0]);a[2][0]=b[4];a[0][1]=(b[2]*b[4]*b[1])+(b[3]*b[0]);a[1][1]=(b[3]*b[1])-(b[2]*b[4]*b[0]);a[2][1]=-(b[2]*b[5]);a[0][2]=(b[2]*b[0])-(b[3]*b[4]*b[1]);a[1][2]=(b[2]*b[1])+(b[3]*b[4]*b[0]);a[2][2]=b[3]*b[5]},transformToWorld:function(){},executePipeline:function(){this.ogamma+=this.addgamma;this.otheta+=this.addtheta;this.ophi+=this.addphi;this.offx+=this.velx;this.offy+=this.vely;this.offz+=this.velz;if(this.offx<this.bminx||this.offx>this.bmaxx){this.velx*=-1}if(this.offy<this.bminy||this.offy>this.bmaxy){this.vely*=-1}if(this.offz<this.bminz||this.offz>this.bmaxz){this.velz*=-1}this.calcMatrix();this.transformToWorld()}}})();(function(){K3D.K3DObject=function(){K3D.K3DObject.superclass.constructor.call(this);this.textures=[];return this};extend(K3D.K3DObject,K3D.BaseObject,{controller:null,worldcoords:null,screenx:0,screeny:0,depthscale:0,linescale:2,color:null,drawmode:"point",shademode:"depthcue",sortmode:"sorted",fillstroke:true,perslevel:512,scale:0,recalculateNormals:false,points:null,edges:null,faces:null,screencoords:null,averagez:null,textures:null,depthcueColors:null,init:function(v,l,f){this.points=v;this.edges=l;this.faces=f;this.worldcoords=new Array(v.length+f.length);for(var n=0,k=this.worldcoords.length;n<k;n++){this.worldcoords[n]={x:0,y:0,z:0}}this.screencoords=new Array(v.length);for(var n=0,k=this.screencoords.length;n<k;n++){this.screencoords[n]={x:0,y:0}}if(this.scale!==0){for(var n=0,k=this.points.length;n<k;n++){v[n].x*=this.scale;v[n].y*=this.scale;v[n].z*=this.scale}}if(this.color===null){this.color=[255,255,255]}this.depthcueColors=new Array(256);for(var q=0,a,o,t;q<256;q++){a=this.color[0]*(q/255);o=this.color[1]*(q/255);t=this.color[2]*(q/255);this.depthcueColors[q]="rgb("+Ceil(a)+","+Ceil(o)+","+Ceil(t)+")"}for(var n=0,k=f.length,p,e,u,m,d,s,h;n<k;n++){p=f[n].vertices;e=v[p[1]].x-v[p[0]].x;u=v[p[1]].y-v[p[0]].y;m=v[p[1]].z-v[p[0]].z;d=v[p[2]].x-v[p[0]].x;s=v[p[2]].y-v[p[0]].y;h=v[p[2]].z-v[p[0]].z;f[n].normal=calcNormalVector(e,u,m,d,s,h);if(!f[n].color){f[n].color=this.color}if(f[n].texture===undefined){f[n].texture=null}}},setController:function(a,b,c){this.controller=a;if(b){this.screenx=b/2;this.screeny=c/2;this.depthscale=this.screenx;this.bminx=-this.screenx;this.bminy=-this.screeny;this.bminz=-this.screenx;this.bmaxx=this.screenx;this.bmaxy=this.screeny;this.bmaxz=this.screenx}},transformToWorld:function(){var k,h,f;var p=this.points,e=this.worldcoords,b=this.faces,n=this.matrix;var l=this.aboutx,j=this.abouty,g=this.aboutz,d=this.offx,c=this.offy,a=this.offz;var r=n[0],o=n[1],m=n[2];for(var q=0,s=p.length;q<s;q++){k=p[q].x+l;h=p[q].y+j;f=p[q].z+g;e[q].x=(r[0]*k)+(r[1]*h)+(r[2]*f)+d;e[q].y=(o[0]*k)+(o[1]*h)+(o[2]*f)+c;e[q].z=(m[0]*k)+(m[1]*h)+(m[2]*f)+a}for(var q=0,s=b.length,t;q<s;q++){t=b[q].normal;k=t.x;h=t.y;f=t.z;b[q].worldnormal=new Vector3D((r[0]*k)+(r[1]*h)+(r[2]*f),(o[0]*k)+(o[1]*h)+(o[2]*f),(m[0]*k)+(m[1]*h)+(m[2]*f))}},transformToScreen:function(){var h,f,e;var a=this.worldcoords,g=this.screencoords;var k=this.screenx,j=this.screeny,d=this.perslevel;for(var b=0,c=this.points.length;b<c;b++){h=a[b].x;f=a[b].y;e=a[b].z+d;if(e===0){e=0.001}g[b].x=((h*d)/e)+k;g[b].y=j-((f*d)/e)}},executePipeline:function(){if(this.recalculateNormals){var c=this.faces,m=this.points;for(var g=0,e=c.length,h,b,l,f,a,k,d;g<e;g++){h=c[g].vertices;b=m[h[1]].x-m[h[0]].x;l=m[h[1]].y-m[h[0]].y;f=m[h[1]].z-m[h[0]].z;a=m[h[2]].x-m[h[0]].x;k=m[h[2]].y-m[h[0]].y;d=m[h[2]].z-m[h[0]].z;c[g].normal=calcNormalVector(b,l,f,a,k,d)}}K3D.K3DObject.superclass.executePipeline.call(this);this.transformToScreen();this.controller.getRenderer(this.drawmode).sortByDistance(this)},executeRenderer:function(a){this.controller.getRenderer(this.drawmode).renderObject(this,a)},calculateAverageZ:function(){var d=0,c=this.worldcoords;for(var b=0,a=this.points.length;b<a;b++){d+=c[b].z}this.averagez=d/this.points.length}})})();(function(){K3D.LightSource=function(b,c,a){K3D.LightSource.superclass.constructor.call(this);this.location=b;this.color=c;this.intensity=a;return this};extend(K3D.LightSource,K3D.BaseObject,{color:null,intensity:null,location:null,worldvector:null,transformToWorld:function(){var b=this.matrix;var a=this.location.x+this.aboutx;var d=this.location.y+this.abouty;var c=this.location.z+this.aboutz;this.worldvector=new Vector3D((b[0][0]*a)+(b[0][1]*d)+(b[0][2]*c)+this.offx,(b[1][0]*a)+(b[1][1]*d)+(b[1][2]*c)+this.offy,(b[2][0]*a)+(b[2][1]*d)+(b[2][2]*c)+this.offz)}})})();(function(){K3D.Renderer=function(){};K3D.Renderer.prototype={sortByDistance:function(a){},renderObject:function(b,a){}}})();(function(){K3D.PointRenderer=function(){K3D.PointRenderer.superclass.constructor.call(this);return this};extend(K3D.PointRenderer,K3D.Renderer,{sortByDistance:function(a){if(a.shademode!=="plain"&&a.sortmode==="sorted"){this.quickSortObject(a.screencoords,a.worldcoords,0,a.points.length-1)}},quickSortObject:function(h,c,i,d){var e=i,g=d,f;var b;if(d>i){f=c[(i+d)>>1].z/2;while(e<=g){while(e<d&&c[e].z>f){e++}while(g>i&&c[g].z<f){g--}if(e<=g){b=h[e];h[e]=h[g];h[g]=b;b=c[e];c[e]=c[g];c[g]=b;e++;g--}}if(i<g){this.quickSortObject(h,c,i,g)}if(e<d){this.quickSortObject(h,c,e,d)}}},renderObject:function(f,m){var b,h,k;var j=f.screencoords,d=f.worldcoords,n=f.depthscale,a=n/128,l=f.linescale/255;for(var e=0,g=f.points.length;e<g;e++){h=d[e].z+n;h=h/a;switch(f.shademode){case"lightsource":case"plain":m.fillStyle="rgb("+f.color[0]+","+f.color[1]+","+f.color[2]+")";break;case"depthcue":if(h<0){h=0}else{if(h>255){h=255}}h=255-Ceil(h);m.fillStyle=f.depthcueColors[h];break}k=l*h;if(k<0.1){k=0.1}m.beginPath();m.arc(j[e].x,j[e].y,k,0,TWOPI,true);m.closePath();m.fill()}}})})();(function(){K3D.WireframeRenderer=function(){K3D.WireframeRenderer.superclass.constructor.call(this);return this};extend(K3D.WireframeRenderer,K3D.Renderer,{sortByDistance:function(a){if(a.shademode!=="plain"&&a.sortmode==="sorted"){this.quickSortObject(a.worldcoords,a.edges,0,a.edges.length-1)}},quickSortObject:function(i,b,h,c){var d=h,g=c,e;var f;if(c>h){e=((i[(b[(h+c)>>1].a)].z)+(i[(b[(h+c)>>1].b)].z))/2;while(d<=g){while((d<c)&&((i[(b[d].a)].z+i[(b[d].b)].z)/2>e)){d++}while((g>h)&&((i[(b[g].a)].z+i[(b[g].b)].z)/2<e)){g--}if(d<=g){f=b[d];b[d]=b[g];b[g]=f;d++;g--}}if(h<g){this.quickSortObject(i,b,h,g)}if(d<c){this.quickSortObject(i,b,d,c)}}},renderObject:function(h,q){var k,n,m,o;var f=h.edges,l=h.screencoords,e=h.worldcoords;var r=h.depthscale,d=r/128,p=h.linescale/255;q.lineWidth=h.linescale;for(var g=0,j=f.length;g<j;g++){n=f[g].a;m=f[g].b;switch(h.shademode){case"lightsource":case"plain":k=h.color;q.strokeStyle="rgb("+k[0]+","+k[1]+","+k[2]+")";break;case"depthcue":k=((e[n].z+e[m].z)/2)+r;k=k/d;if(k<0){k=0}else{if(k>255){k=255}}k=255-Ceil(k);q.strokeStyle=h.depthcueColors[k];o=p*k;q.lineWidth=(o>0.1?o:0.1);break}q.beginPath();q.moveTo(l[n].x,l[n].y);q.lineTo(l[m].x,l[m].y);q.closePath();q.stroke()}}})})();(function(){K3D.SolidRenderer=function(){K3D.SolidRenderer.superclass.constructor.call(this);return this};extend(K3D.SolidRenderer,K3D.Renderer,{sortByDistance:function b(e){if(e.sortmode==="sorted"){this.quickSortObject(e.worldcoords,e.faces,0,e.faces.length-1)}},quickSortObject:function a(h,r,g,s){var q=g,f=s,p,o,n,e;if(s>g){n=r[(g+s)>>1].vertices;for(var l=0,k=n.length,m=0;l<k;l++){m+=h[n[l]].z}p=m/n.length;while(q<=f){while(true){n=r[q].vertices;for(var l=0,k=n.length,m=0;l<k;l++){m+=(h[n[l]].z)}e=m/n.length;if(q<s&&e>p){q++}else{break}}while(true){n=r[f].vertices;for(var l=0,k=n.length,m=0;l<k;l++){m+=h[n[l]].z}e=m/n.length;if(f>g&&e<p){f--}else{break}}if(q<=f){o=r[q];r[q]=r[f];r[f]=o;q++;f--}}if(g<f){this.quickSortObject(h,r,g,f)}if(q<s){this.quickSortObject(h,r,q,s)}}},renderObject:function c(w,A){var h=w.faces,k=w.screencoords,p=w.worldcoords;var m=w.depthscale,I=m/128;var x=new Vector3D(0,0,1);var s,y,E,H,G,v=PI/2,q;var K=w.controller.lights;var J=w.doublesided;for(var z=0,D=h.length,u;z<D;z++){u=h[z];s=u.vertices;var F=x.thetaTo2(u.worldnormal);if(J||(F+0.15>v)){switch(w.shademode){case"plain":if(u.texture===null){G=u.color;q="rgb("+G[0]+","+G[1]+","+G[2]+")";this.renderPolygon(A,w,u,q)}else{this.renderPolygon(A,w,u)}break;case"depthcue":for(var C=0,B=s.length,t=0;C<B;C++){t+=p[s[C]].z}var o=((t/s.length)+m)/I;if(o<0){o=0}else{if(o>255){o=255}}if(u.texture===null){o=(255-o)/255;G=u.color;y=Ceil(o*G[0]);E=Ceil(o*G[1]);H=Ceil(o*G[2]);q="rgb("+y+","+E+","+H+")"}else{o=255-Ceil(o);q="rgba(0,0,0,"+(1-(o/255))+")"}this.renderPolygon(A,w,u,q);break;case"lightsource":if(K.length===0){G=u.color;y=Ceil(F*(G[0]/PI));E=Ceil(F*(G[1]/PI));H=Ceil(F*(G[2]/PI));if(u.texture===null){q="rgb("+y+","+E+","+H+")"}else{q="rgba(0,0,0,"+(1-F*ONEOPI)+")"}this.renderPolygon(A,w,u,q)}else{y=E=H=0;for(var C=0,B=K.length,l,e;C<B;C++){l=K[C];F=PI-l.worldvector.thetaTo2(u.worldnormal);e=F*((1/l.worldvector.distance(u.worldnormal))*l.intensity)/PI;y+=(e*l.color[0]);E+=(e*l.color[1]);H+=(e*l.color[2])}if(y>1){y=1}if(E>1){E=1}if(H>1){H=1}G=u.color;var f=Ceil(y*G[0])+","+Ceil(E*G[1])+","+Ceil(H*G[2]);if(u.texture===null){q="rgb("+f+")"}else{q="rgba("+f+","+(1-(y+E+H)*0.33333)+")"}this.renderPolygon(A,w,u,q)}break}}}},renderPolygon:function d(q,g,l,p){var m=g.screencoords,k=l.vertices;q.save();if(l.texture===null){q.beginPath();q.moveTo(m[k[0]].x,m[k[0]].y);for(var h=1,e=k.length;h<e;h++){q.lineTo(m[k[h]].x,m[k[h]].y)}q.closePath();q.fillStyle=p;q.fill();if(g.fillstroke){q.fill()}}else{var n=g.textures[l.texture];var f=function(C,z,H,y,F,x,D){q.save();q.beginPath();q.moveTo(m[C[0]].x,m[C[0]].y);for(var G=1,E=C.length;G<E;G++){q.lineTo(m[C[G]].x,m[C[G]].y)}q.closePath();q.clip();var K=m[C[0]].x,u=m[C[0]].y,J=m[C[1]].x,t=m[C[1]].y,I=m[C[2]].x,s=m[C[2]].y;var r=r=1/(z*(D-F)-y*D+x*F+(y-x)*H);var M=-(H*(I-J)-F*I+D*J+(F-D)*K)*r,L=(F*s+H*(t-s)-D*t+(D-F)*u)*r,w=(z*(I-J)-y*I+x*J+(y-x)*K)*r,v=-(y*s+z*(t-s)-x*t+(x-y)*u)*r,B=(z*(D*J-F*I)+H*(y*I-x*J)+(x*F-y*D)*K)*r,A=(z*(D*t-F*s)+H*(y*s-x*t)+(x*F-y*D)*u)*r;q.transform(M,L,w,v,B,A);q.drawImage(n,0,0);if(p){q.fillStyle=p;q.fill()}q.restore()};f.call(this,k.slice(0,3),0,0,n.width,0,n.width,n.height);if(k.length===4){var o=[];o.push(k[2]);o.push(k[3]);o.push(k[0]);f.call(this,o,n.width,n.height,0,n.height,0,0)}}q.restore()}})})();
1  public/scripts/mathlib-min.js
@@ -0,0 +1 @@
+var RAD=Math.PI/180;var PI=Math.PI;var TWOPI=Math.PI*2;var ONEOPI=1/Math.PI;var PIO2=Math.PI/2;var PIO4=Math.PI/4;var PIO8=Math.PI/8;var PIO16=Math.PI/16;var PIO32=Math.PI/32;var Rnd=Math.random;var Sin=Math.sin;var Cos=Math.cos;var Sqrt=Math.sqrt;var Floor=Math.floor;var Atan2=Math.atan2;var Ceil=Math.ceil;function randomInt(a,b){return ~~(Rnd()*(b-a+1)+a)}function weightedRandom(b){var a=Rnd();if(a<0.5){return 1-Math.pow(1-a,b!==undefined?b:2)/2}return 0.5+Math.pow((a-0.5)*2,b!==undefined?b:2)/2}function calcNormalVector(b,d,f,a,c,e){return new Vector3D((d*e)-(f*c),-((e*b)-(a*f)),(b*c)-(d*a)).norm()}function extend(d,e,c){var b=function(){},a;b.prototype=e.prototype;d.prototype=new b();d.prototype.constructor=d;d.superclass=e.prototype;if(e.prototype.constructor==Object.prototype.constructor){e.prototype.constructor=e}if(c){for(a in c){if(c.hasOwnProperty(a)){d.prototype[a]=c[a]}}}}function isArray(a){return(a.constructor.toString().indexOf("Array")!==-1)}(function(){Vector=function(x,y){this.x=x;this.y=y;return this};Vector.prototype={x:0,y:0,clone:function(){return new Vector(this.x,this.y)},set:function(v){this.x=v.x;this.y=v.y;return this},add:function(v){this.x+=v.x;this.y+=v.y;return this},nadd:function(v){return new Vector(this.x+v.x,this.y+v.y)},sub:function(v){this.x-=v.x;this.y-=v.y;return this},nsub:function(v){return new Vector(this.x-v.x,this.y-v.y)},dot:function(v){return this.x*v.x+this.y*v.y},length:function(){return Sqrt(this.x*this.x+this.y*this.y)},distance:function(v){var xx=this.x-v.x;var yy=this.y-v.y;return Sqrt(xx*xx+yy*yy)},theta:function(){return Atan2(this.y,this.x)},thetaTo:function(vec){var v=this.clone().norm();var w=vec.clone().norm();return Math.acos(v.dot(w))},thetaTo2:function(vec){return Atan2(vec.y,vec.x)-Atan2(this.y,this.x)},norm:function(){var len=this.length();this.x/=len;this.y/=len;return this},nnorm:function(){var len=this.length();return new Vector(this.x/len,this.y/len)},rotate:function(a){var ca=Cos(a);var sa=Sin(a);with(this){var rx=x*ca-y*sa;var ry=x*sa+y*ca;x=rx;y=ry}return this},nrotate:function(a){var ca=Cos(a),sa=Sin(a);return new Vector(this.x*ca-this.y*sa,this.x*sa+this.y*ca)},invert:function(){this.x=-this.x;this.y=-this.y;return this},ninvert:function(){return new Vector(-this.x,-this.y)},scale:function(s){this.x*=s;this.y*=s;return this},nscale:function(s){return new Vector(this.x*s,this.y*s)},scaleTo:function(s){var len=s/this.length();this.x*=len;this.y*=len;return this},nscaleTo:function(s){var len=s/this.length();return new Vector(this.x*len,this.y*len)}}})();(function(){Vector3D=function(a,c,b){this.x=a;this.y=c;this.z=b;return this};Vector3D.prototype={x:0,y:0,z:0,clone:function(){return new Vector3D(this.x,this.y,this.z)},set:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},sub:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},cross:function(a){return new Vector3D(this.y*a.z-this.z*a.y,this.z*a.x-this.x*a.z,this.x*a.y-this.y*a.x)},length:function(){return Sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},distance:function(b){var c=this.x-b.x;var d=this.y-b.y;var a=this.z-b.z;return Sqrt(c*c+d*d+a*a)},thetaTo:function(b){var a=this.y*b.z-this.z*b.y,d=this.z*b.x-this.x*b.z,c=this.x*b.y-this.y*b.x;return Atan2(Sqrt(a*a+d*d+c*c),this.dot(b))},thetaTo2:function(a){return Math.acos(this.dot(a)/(Sqrt(this.x*this.x+this.y*this.y+this.z*this.z)*Sqrt(a.x*a.x+a.y*a.y+a.z*a.z)))},norm:function(){var a=this.length();this.x/=a;this.y/=a;this.z/=a;return this},scale:function(a){this.x*=a;this.y*=a;this.z*=a;return this}}})();(function(){Preloader=function(){this.images=new Array();return this};Preloader.prototype={images:null,callback:null,counter:0,addImage:function b(c,d){var e=this;c.url=d;c.onload=function(){e.counter++;if(e.counter===e.images.length){e.callback.call(e)}};this.images.push(c)},onLoadCallback:function a(e){this.counter=0;this.callback=e;for(var d=0,c=this.images.length;d<c;d++){this.images[d].src=this.images[d].url}}}})();
Please sign in to comment.
Something went wrong with that request. Please try again.