merge conflicts

beta.r3js.org
Theunis J. Botha 2016-10-28 10:00:05 +02:00
commit dcb598d778
54 changed files with 22507 additions and 728 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,213 @@
body, html {
margin:0; padding: 0;
height: 100%;
}
body {
font-family: Helvetica Neue, Helvetica, Arial;
font-size: 14px;
color:#333;
}
.small { font-size: 12px; }
*, *:after, *:before {
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
}
h1 { font-size: 20px; margin: 0;}
h2 { font-size: 14px; }
pre {
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
margin: 0;
padding: 0;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
}
a { color:#0074D9; text-decoration:none; }
a:hover { text-decoration:underline; }
.strong { font-weight: bold; }
.space-top1 { padding: 10px 0 0 0; }
.pad2y { padding: 20px 0; }
.pad1y { padding: 10px 0; }
.pad2x { padding: 0 20px; }
.pad2 { padding: 20px; }
.pad1 { padding: 10px; }
.space-left2 { padding-left:55px; }
.space-right2 { padding-right:20px; }
.center { text-align:center; }
.clearfix { display:block; }
.clearfix:after {
content:'';
display:block;
height:0;
clear:both;
visibility:hidden;
}
.fl { float: left; }
@media only screen and (max-width:640px) {
.col3 { width:100%; max-width:100%; }
.hide-mobile { display:none!important; }
}
.quiet {
color: #7f7f7f;
color: rgba(0,0,0,0.5);
}
.quiet a { opacity: 0.7; }
.fraction {
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
font-size: 10px;
color: #555;
background: #E8E8E8;
padding: 4px 5px;
border-radius: 3px;
vertical-align: middle;
}
div.path a:link, div.path a:visited { color: #333; }
table.coverage {
border-collapse: collapse;
margin: 10px 0 0 0;
padding: 0;
}
table.coverage td {
margin: 0;
padding: 0;
vertical-align: top;
}
table.coverage td.line-count {
text-align: right;
padding: 0 5px 0 20px;
}
table.coverage td.line-coverage {
text-align: right;
padding-right: 10px;
min-width:20px;
}
table.coverage td span.cline-any {
display: inline-block;
padding: 0 5px;
width: 100%;
}
.missing-if-branch {
display: inline-block;
margin-right: 5px;
border-radius: 3px;
position: relative;
padding: 0 4px;
background: #333;
color: yellow;
}
.skip-if-branch {
display: none;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: #ccc;
color: white;
}
.missing-if-branch .typ, .skip-if-branch .typ {
color: inherit !important;
}
.coverage-summary {
border-collapse: collapse;
width: 100%;
}
.coverage-summary tr { border-bottom: 1px solid #bbb; }
.keyline-all { border: 1px solid #ddd; }
.coverage-summary td, .coverage-summary th { padding: 10px; }
.coverage-summary tbody { border: 1px solid #bbb; }
.coverage-summary td { border-right: 1px solid #bbb; }
.coverage-summary td:last-child { border-right: none; }
.coverage-summary th {
text-align: left;
font-weight: normal;
white-space: nowrap;
}
.coverage-summary th.file { border-right: none !important; }
.coverage-summary th.pct { }
.coverage-summary th.pic,
.coverage-summary th.abs,
.coverage-summary td.pct,
.coverage-summary td.abs { text-align: right; }
.coverage-summary td.file { white-space: nowrap; }
.coverage-summary td.pic { min-width: 120px !important; }
.coverage-summary tfoot td { }
.coverage-summary .sorter {
height: 10px;
width: 7px;
display: inline-block;
margin-left: 0.5em;
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
}
.coverage-summary .sorted .sorter {
background-position: 0 -20px;
}
.coverage-summary .sorted-desc .sorter {
background-position: 0 -10px;
}
.status-line { height: 10px; }
/* dark red */
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
.low .chart { border:1px solid #C21F39 }
/* medium red */
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
/* light red */
.low, .cline-no { background:#FCE1E5 }
/* light green */
.high, .cline-yes { background:rgb(230,245,208) }
/* medium green */
.cstat-yes { background:rgb(161,215,106) }
/* dark green */
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
.high .chart { border:1px solid rgb(77,146,33) }
/* dark yellow (gold) */
.medium .chart { border:1px solid #f9cd0b; }
.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
/* light yellow */
.medium { background: #fff4c2; }
/* light gray */
span.cline-neutral { background: #eaeaea; }
.cbranch-no { background: yellow !important; color: #111; }
.cstat-skip { background: #ddd; color: #111; }
.fstat-skip { background: #ddd; color: #111 !important; }
.cbranch-skip { background: #ddd !important; color: #111; }
.cover-fill, .cover-empty {
display:inline-block;
height: 12px;
}
.chart {
line-height: 0;
}
.cover-empty {
background: white;
}
.cover-full {
border-right: none !important;
}
pre.prettyprint {
border: none !important;
padding: 0 !important;
margin: 0 !important;
}
.com { color: #999 !important; }
.ignore-none { color: #999; font-weight: normal; }
.wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 auto -48px;
}
.footer, .push {
height: 48px;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for build/</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../prettify.css" />
<link rel="stylesheet" href="../base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="../index.html">all files</a> build/
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">17.71% </span>
<span class="quiet">Statements</span>
<span class='fraction'>309/1745</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">3.87% </span>
<span class="quiet">Branches</span>
<span class='fraction'>27/697</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">6.16% </span>
<span class="quiet">Functions</span>
<span class='fraction'>9/146</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">17.71% </span>
<span class="quiet">Lines</span>
<span class='fraction'>309/1745</span>
</div>
</div>
</div>
<div class='status-line low'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file low" data-value="game-lib.js"><a href="game-lib.js.html">game-lib.js</a></td>
<td data-value="17.71" class="pic low"><div class="chart"><div class="cover-fill" style="width: 17%;"></div><div class="cover-empty" style="width:83%;"></div></div></td>
<td data-value="17.71" class="pct low">17.71%</td>
<td data-value="1745" class="abs low">309/1745</td>
<td data-value="3.87" class="pct low">3.87%</td>
<td data-value="697" class="abs low">27/697</td>
<td data-value="6.16" class="pct low">6.16%</td>
<td data-value="146" class="abs low">9/146</td>
<td data-value="17.71" class="pct low">17.71%</td>
<td data-value="1745" class="abs low">309/1745</td>
</tr>
</tbody>
</table>
</div><div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Tue Oct 18 2016 15:35:01 GMT+0200 (CEST)
</div>
</div>
<script src="../prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="../sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,93 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for All files</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="prettify.css" />
<link rel="stylesheet" href="base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
/
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">17.71% </span>
<span class="quiet">Statements</span>
<span class='fraction'>309/1745</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">3.87% </span>
<span class="quiet">Branches</span>
<span class='fraction'>27/697</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">6.16% </span>
<span class="quiet">Functions</span>
<span class='fraction'>9/146</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">17.71% </span>
<span class="quiet">Lines</span>
<span class='fraction'>309/1745</span>
</div>
</div>
</div>
<div class='status-line low'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file low" data-value="build/"><a href="build/index.html">build/</a></td>
<td data-value="17.71" class="pic low"><div class="chart"><div class="cover-fill" style="width: 17%;"></div><div class="cover-empty" style="width:83%;"></div></div></td>
<td data-value="17.71" class="pct low">17.71%</td>
<td data-value="1745" class="abs low">309/1745</td>
<td data-value="3.87" class="pct low">3.87%</td>
<td data-value="697" class="abs low">27/697</td>
<td data-value="6.16" class="pct low">6.16%</td>
<td data-value="146" class="abs low">9/146</td>
<td data-value="17.71" class="pct low">17.71%</td>
<td data-value="1745" class="abs low">309/1745</td>
</tr>
</tbody>
</table>
</div><div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Tue Oct 18 2016 15:35:01 GMT+0200 (CEST)
</div>
</div>
<script src="prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1 @@
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

View File

@ -0,0 +1,158 @@
var addSorting = (function () {
"use strict";
var cols,
currentSort = {
index: 0,
desc: false
};
// returns the summary table element
function getTable() { return document.querySelector('.coverage-summary'); }
// returns the thead element of the summary table
function getTableHeader() { return getTable().querySelector('thead tr'); }
// returns the tbody element of the summary table
function getTableBody() { return getTable().querySelector('tbody'); }
// returns the th element for nth column
function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
// loads all columns
function loadColumns() {
var colNodes = getTableHeader().querySelectorAll('th'),
colNode,
cols = [],
col,
i;
for (i = 0; i < colNodes.length; i += 1) {
colNode = colNodes[i];
col = {
key: colNode.getAttribute('data-col'),
sortable: !colNode.getAttribute('data-nosort'),
type: colNode.getAttribute('data-type') || 'string'
};
cols.push(col);
if (col.sortable) {
col.defaultDescSort = col.type === 'number';
colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
}
}
return cols;
}
// attaches a data attribute to every tr element with an object
// of data values keyed by column name
function loadRowData(tableRow) {
var tableCols = tableRow.querySelectorAll('td'),
colNode,
col,
data = {},
i,
val;
for (i = 0; i < tableCols.length; i += 1) {
colNode = tableCols[i];
col = cols[i];
val = colNode.getAttribute('data-value');
if (col.type === 'number') {
val = Number(val);
}
data[col.key] = val;
}
return data;
}
// loads all row data
function loadData() {
var rows = getTableBody().querySelectorAll('tr'),
i;
for (i = 0; i < rows.length; i += 1) {
rows[i].data = loadRowData(rows[i]);
}
}
// sorts the table using the data for the ith column
function sortByIndex(index, desc) {
var key = cols[index].key,
sorter = function (a, b) {
a = a.data[key];
b = b.data[key];
return a < b ? -1 : a > b ? 1 : 0;
},
finalSorter = sorter,
tableBody = document.querySelector('.coverage-summary tbody'),
rowNodes = tableBody.querySelectorAll('tr'),
rows = [],
i;
if (desc) {
finalSorter = function (a, b) {
return -1 * sorter(a, b);
};
}
for (i = 0; i < rowNodes.length; i += 1) {
rows.push(rowNodes[i]);
tableBody.removeChild(rowNodes[i]);
}
rows.sort(finalSorter);
for (i = 0; i < rows.length; i += 1) {
tableBody.appendChild(rows[i]);
}
}
// removes sort indicators for current column being sorted
function removeSortIndicators() {
var col = getNthColumn(currentSort.index),
cls = col.className;
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
col.className = cls;
}
// adds sort indicators for current column being sorted
function addSortIndicators() {
getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
}
// adds event listeners for all sorter widgets
function enableUI() {
var i,
el,
ithSorter = function ithSorter(i) {
var col = cols[i];
return function () {
var desc = col.defaultDescSort;
if (currentSort.index === i) {
desc = !currentSort.desc;
}
sortByIndex(i, desc);
removeSortIndicators();
currentSort.index = i;
currentSort.desc = desc;
addSortIndicators();
};
};
for (i =0 ; i < cols.length; i += 1) {
if (cols[i].sortable) {
// add the click event handler on the th so users
// dont have to click on those tiny arrows
el = getNthColumn(i).querySelector('.sorter').parentElement;
if (el.addEventListener) {
el.addEventListener('click', ithSorter(i));
} else {
el.attachEvent('onclick', ithSorter(i));
}
}
}
}
// adds sorting functionality to the UI
return function () {
if (!getTable()) {
return;
}
cols = loadColumns();
loadData(cols);
addSortIndicators();
enableUI();
};
})();
window.addEventListener('load', addSorting);

2743
build/coverage/lcov.info Normal file

File diff suppressed because it is too large Load Diff

2
build/game-lib-min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
config.js Symbolic link
View File

@ -0,0 +1 @@
../config/config.js

View File

@ -1,704 +0,0 @@
function Maths3D() {}
Maths3D.Vector2 = function(x, y) {
this.x = 0;
this.y = 0;
if (x) {
this.x = x;
}
if (y) {
this.y = y;
}
};
Maths3D.Vector3 = function(x, y, z) {
this.x = 0;
this.y = 0;
this.z = 0;
if (x) {
this.x = x;
}
if (y) {
this.y = y;
}
if (z) {
this.z = z;
}
};
Maths3D.Vector4 = function(x, y, z, w) {
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 0;
if (x) {
this.x = x;
}
if (y) {
this.y = y;
}
if (z) {
this.z = z;
}
if (w) {
this.w = w;
}
};
Maths3D.Matrix3 = function(
row0,
row1,
row2
) {
this.identity();
if (row0) {
this.rows[0] = row0;
}
if (row1) {
this.rows[1] = row1;
}
if (row2) {
this.rows[2] = row2;
}
};
Maths3D.Matrix4 = function(
row0,
row1,
row2,
row3
) {
this.identity();
if (row0) {
this.rows[0] = row0;
}
if (row1) {
this.rows[1] = row1;
}
if (row2) {
this.rows[2] = row2;
}
if (row3) {
this.rows[3] = row3;
}
};
Maths3D.Color = function(r, g, b, a) {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
};
Maths3D.Vector2.prototype.copy = function() {
return new Maths3D.Vector2(
this.x,
this.y
);
};
Maths3D.Vector2.prototype.equals = function(v) {
return !!(((this.x == v.x) &&
(this.y == v.y)) ||
((this.y == v.x) &&
(this.x == v.y)));
};
Maths3D.Matrix4.prototype.rotationMatrixX = function (radians) {
this.identity();
this.rows[1] = new Maths3D.Vector4(0, Math.cos(radians), -1 * Math.sin(radians), 0);
this.rows[2] = new Maths3D.Vector4(0, Math.sin(radians), Math.cos(radians), 0);
return this;
};
Maths3D.Matrix4.prototype.rotationMatrixY = function (radians) {
this.identity();
this.rows[0] = new Maths3D.Vector4(
Math.cos(radians),
0,
Math.sin(radians),
0
);
this.rows[2] = new Maths3D.Vector4(
-1 * Math.sin(radians),
0,
Math.cos(radians),
0
);
return this;
};
Maths3D.Matrix4.prototype.rotationMatrixZ = function (radians) {
this.identity();
this.rows[0] = new Maths3D.Vector4(Math.cos(radians), -1 * Math.sin(radians), 0, 0);
this.rows[1] = new Maths3D.Vector4(Math.sin(radians), Math.cos(radians), 0, 0);
return this;
};
Maths3D.Matrix4.prototype.rotateX = function (radians, point) {
this.identity();
this.rotationMatrixX(radians);
return this.multiply(point);
};
Maths3D.Matrix4.prototype.rotateY = function (radians, point) {
this.identity();
this.rotationMatrixY(radians);
return this.multiply(point);
};
Maths3D.Matrix4.prototype.rotateZ = function (radians, point) {
this.identity();
this.rotationMatrixZ(radians);
return this.multiply(point);
};
Maths3D.Matrix4.prototype.multiply = function (mvp) {
if (mvp instanceof Maths3D.Vector4) {
return new Maths3D.Vector4(
this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z + this.rows[0].w * mvp.w,
this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z + this.rows[1].w * mvp.w,
this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z + this.rows[2].w * mvp.w,
this.rows[3].x * mvp.x + this.rows[3].y * mvp.y + this.rows[3].z * mvp.z + this.rows[3].w * mvp.w
);
} else if (mvp instanceof Maths3D.Vector3) {
return new Maths3D.Vector3(
this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z,
this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z,
this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z
);
}
};
Maths3D.Vector4.Points = function () {
this.vectors = [];
};
Maths3D.Vector4.Points.prototype.add = function (vector) {
if (vector instanceof Maths3D.Vector3) {
vector = new Maths3D.Vector4(
vector.x,
vector.y,
vector.z,
1
)
}
if (!vector instanceof Maths3D.Vector4) {
console.warn("Vector needs to be of type Vector4");
throw new Error("Vector needs to be of type Vector4");
}
this.vectors.push(vector);
return this;
};
Maths3D.Vector4.Points.prototype.copy = function () {
var vectors = [];
for (var i = 0; i < this.vectors.length; i++) {
vectors.push(this.vectors[i].copy());
}
return vectors;
};
Maths3D.Vector4.Points.prototype.maximizeXDistance = function (grain) {
// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
var multiplier = 0;
var rotationMatrixY = new Maths3D.Matrix4().rotationMatrixY(grain);
var totalRadians = 0;
var backupVectors = this.copy();
var maxXDistance = 0;
for (var i = 0; i < Math.PI * 2; i += grain) {
multiplier++;
for (var j = 0; j < this.vectors.length; j++) {
this.vectors[j] = rotationMatrixY.multiply(this.vectors[j]);
}
var distances = this.distances();
if (distances.x > maxXDistance) {
maxXDistance = distances.x;
totalRadians = multiplier * grain;
}
}
this.vectors = backupVectors;
// console.log("distance: " + maxXDistance + " radians : " + totalRadians);
var maxRotationMatrix = new Maths3D.Matrix4().rotationMatrixY(totalRadians);
for (var k = 0; k < this.vectors.length; k++) {
this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
}
// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
};
Maths3D.Vector4.Points.prototype.maximizeYDistance = function (grain) {
// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
var multiplier = 0;
var rotationMatrixX = new Maths3D.Matrix4().rotationMatrixX(grain);
var totalRadians = 0;
var backupVectors = this.copy();
var maxYDistance = 0;
for (var i = 0; i < Math.PI * 2; i += grain) {
multiplier++;
for (var j = 0; j < this.vectors.length; j++) {
this.vectors[j] = rotationMatrixX.multiply(this.vectors[j]);
}
var distances = this.distances();
if (distances.y > maxYDistance) {
maxYDistance = distances.y;
totalRadians = multiplier * grain;
}
}
this.vectors = backupVectors;
// console.log("distance: " + maxYDistance + " radians : " + totalRadians);
var maxRotationMatrix = new Maths3D.Matrix4().rotationMatrixX(totalRadians);
for (var k = 0; k < this.vectors.length; k++) {
this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
}
// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
};
Maths3D.Vector4.Points.prototype.lookAt = function (at, up) {
var polyCenter = this.average();
console.log("poly center : " + JSON.stringify(polyCenter));
var lookAtMatrix = new Maths3D.Matrix4().lookAt(polyCenter, at, up);
lookAtMatrix.rows[0] = new Maths3D.Vector4(1, 0, 0, 0);
lookAtMatrix.rows[1] = new Maths3D.Vector4(0, 0, 1, 0);
lookAtMatrix.rows[2] = new Maths3D.Vector4(0, 1, 0, 0);
console.log("look at matrix : " + JSON.stringify(lookAtMatrix, null, 2));
for (var i = 0; i < this.vectors.length; i++) {
console.log("vector " + i + " (before): " + JSON.stringify(this.vectors[i]));
this.vectors[i] = lookAtMatrix.multiply(this.vectors[i]);
console.log("vector " + i + " (after) : " + JSON.stringify(this.vectors[i]));
}
};
Maths3D.Vector4.Points.prototype.distances = function () {
var minX = this.vectors[0].x;
var minY = this.vectors[0].y;
var minZ = this.vectors[0].z;
var maxX = this.vectors[0].x;
var maxY = this.vectors[0].y;
var maxZ = this.vectors[0].z;
for (var i = 0; i < this.vectors.length; i++) {
if (this.vectors[i].x < minX) {
minX = this.vectors[i].x;
}
if (this.vectors[i].y < minY) {
minY = this.vectors[i].y;
}
if (this.vectors[i].z < minZ) {
minZ = this.vectors[i].z;
}
if (this.vectors[i].x > maxX) {
maxX = this.vectors[i].x;
}
if (this.vectors[i].y > maxY) {
maxY = this.vectors[i].y;
}
if (this.vectors[i].z > maxZ) {
maxZ = this.vectors[i].z;
}
}
return new Maths3D.Vector3(
Math.abs(maxX - minX),
Math.abs(maxY - minY),
Math.abs(maxY - minZ)
)
};
Maths3D.Vector4.Points.prototype.average = function () {
var averageX = 0;
var averageY = 0;
var averageZ = 0;
for (var i = 0; i < this.vectors.length; i++) {
averageX += this.vectors[i].x;
averageY += this.vectors[i].y;
averageZ += this.vectors[i].z;
}
return new Maths3D.Vector3(
averageX / this.vectors.length,
averageY / this.vectors.length,
averageZ / this.vectors.length
);
};
Maths3D.Vector4.Points.prototype.negative = function () {
for (var i = 0; i < this.vectors.length; i++) {
this.vectors[i].x *= -1;
this.vectors[i].y *= -1;
this.vectors[i].z *= -1;
}
return this;
};
Maths3D.Vector4.Points.prototype.toOrigin = function () {
var distanceFromOrigin = this.average().negative();
for (var i = 0; i < this.vectors.length; i++) {
this.vectors[i].translate(distanceFromOrigin);
}
};
Maths3D.Vector3.clockwise = function (u, v, w, viewPoint) {
var normal = Maths3D.Vector3.normal(u, v, w);
var uv = u.copy();
var winding = normal.dot(uv.subtract(viewPoint));
return (winding > 0);
};
Maths3D.Vector3.normal = function (u, v, w) {
var vv = v.copy();
var wv = w.copy();
return vv.subtract(u).cross(wv.subtract(u));
};
Maths3D.Vector3.prototype.lookAt = function (at, up) {
var lookAtMatrix = Maths3D.Matrix4.lookAt(this, at, up);
this.multiply(lookAtMatrix);
};
Maths3D.Vector3.prototype.translate = function (v) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
};
Maths3D.Vector4.prototype.translate = function (v) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
};
Maths3D.Vector3.prototype.squared = function () {
return this.x * this.x + this.y * this.y + this.z * this.z;
};
Maths3D.Vector3.prototype.copy = function () {
return new Maths3D.Vector3(
this.x,
this.y,
this.z
);
};
Maths3D.Vector4.prototype.copy = function () {
return new Maths3D.Vector4(
this.x,
this.y,
this.z,
this.w
);
};
Maths3D.Vector3.prototype.multiply = function (s) {
if (s instanceof Maths3D.Vector3) {
this.x *= s.x;
this.y *= s.y;
this.z *= s.z;
} else if (s instanceof Maths3D.Matrix4) {
var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z;
var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z;
var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z;
this.x = x;
this.y = y;
this.z = z;
} else {
console.log("functionality not implemented - please do this");
throw new Error("not implemented");
}
return this;
};
Maths3D.Vector4.prototype.multiply = function (s) {
if (s instanceof Maths3D.Vector3) {
this.x *= s.x;
this.y *= s.y;
this.z *= s.z;
} else if (s instanceof Maths3D.Matrix4) {
var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z + s.rows[0].w * this.w;
var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z + s.rows[1].w * this.w;
var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z + s.rows[2].w * this.w;
var w = s.rows[3].x * this.x + s.rows[3].y * this.y + s.rows[3].z * this.z + s.rows[3].w * this.w;
this.x = x;
this.y = y;
this.z = z;
this.w = w;
} else {
console.log("functionality not implemented - please do this");
throw new Error("not implemented");
}
};
Maths3D.Vector3.prototype.dot = function (v) {
return (this.x * v.x) + (this.y * v.y) + (this.z * v.z);
};
Maths3D.Vector3.prototype.normalize = function () {
var EPSILON = 0.000001;
var v2 = this.squared();
if (v2 < EPSILON) {
return this; //do nothing for zero vector
}
var invLength = 1 / Math.sqrt(v2);
this.x *= invLength;
this.y *= invLength;
this.z *= invLength;
return this;
};
Maths3D.Vector4.prototype.normalize = function () {
// note - leave w untouched
var EPSILON = 0.000001;
var v2 = this.x * this.x + this.y * this.y + this.z * this.z;
if (v2 < EPSILON) {
return this; //do nothing for zero vector
}
var invLength = 1 / Math.sqrt(v2);
this.x *= invLength;
this.y *= invLength;
this.z *= invLength;
return this;
};
Maths3D.Matrix3.prototype.identity = function () {
this.rows = [
new Maths3D.Vector4(1, 0, 0),
new Maths3D.Vector4(0, 1, 0),
new Maths3D.Vector4(0, 0, 1)
];
};
Maths3D.Matrix4.prototype.identity = function () {
this.rows = [
new Maths3D.Vector4(1, 0, 0, 0),
new Maths3D.Vector4(0, 1, 0, 0),
new Maths3D.Vector4(0, 0, 1, 0),
new Maths3D.Vector4(0, 0, 0, 1)
];
};
Maths3D.Matrix4.prototype.lookAt = function (position, target, up) {
var pv = new Maths3D.Vector3(position.x, position.y, position.z);
var z = pv.subtract(target).normalize();
if (z.squared() === 0) {
z.z = 1;
}
var x = up.cross(z).normalize();
if (x.squared() === 0) {
z.x += 0.0001;
x = up.cross(z).normalize();
}
var y = z.cross(x);
this.rows[0].x = x.x;
this.rows[0].y = x.y;
this.rows[0].z = x.z;
this.rows[1].x = y.x;
this.rows[1].y = y.y;
this.rows[1].z = y.z;
this.rows[2].x = z.x;
this.rows[2].y = z.y;
this.rows[2].z = z.z;
return this;
// te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
// te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
// te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
// var matrix4 = new Matrix4();
//
// matrix4.rows[0] = side.negative();
// matrix4.rows[1] = _up;
// matrix4.rows[2] = forward;
//
// matrix4.setColumn(0, side.negative());
// matrix4.setColumn(1, _up);
// matrix4.setColumn(2, forward);
//return matrix4;
// return new Matrix4(
// new Vector4(
// side.x,
// side.y,
// side.z,
// side.negative().dot(position)
// ),
// new Vector4(
// _up.x,
// _up.y,
// _up.z,
// _up.negative().dot(position)
// ),
// new Vector4(
// forward.negative().x,
// forward.negative().y,
// forward.negative().z,
// forward.dot(position)
// )
// )
};
Maths3D.Vector3.prototype.negative = function () {
this.x *= -1;
this.y *= -1;
this.z *= -1;
return this;
};
Maths3D.Vector3.prototype.magnitude = function () {
return this.x + this.y + this.z;
};
Maths3D.Vector4.prototype.subtract = function (v) {
if (v instanceof Maths3D.Vector3) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
}
if (v instanceof Maths3D.Vector4) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
this.w -= v.w;
}
return this;
};
Maths3D.Vector3.prototype.subtract = function (v) {
if (v instanceof Maths3D.Vector3) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
}
if (v instanceof Maths3D.Vector4) {
console.warn("trying to subtract vector of bigger length (4 vs 3))");
}
return this;
};
Maths3D.Vector3.prototype.cross = function (v) {
return new Maths3D.Vector3(
this.y * v.z - this.z * v.y,
this.z * v.x - this.x * v.z,
this.x * v.y - this.y * v.x
);
};
if (typeof module !== 'undefined') {
module.exports = Maths3D;
}

24
game.js
View File

@ -1,24 +0,0 @@
function Game() {}
/**
* Games are collections of scenes and physics worlds
* @param id
* @param name
* @param path
* @param scenes THREE.Scene[]
* @param worlds GameLib.D3.Physics.World[]
* @constructor
*/
Game = function(
id,
name,
path,
scenes,
worlds
) {
this.id = id;
this.name = name;
this.path = path;
this.scenes = scenes;
this.worlds = worlds;
};

76
gulpfile.js Normal file
View File

@ -0,0 +1,76 @@
var gulp = require('gulp');
var concat = require('gulp-concat');
var sort = require('gulp-sort');
var minify = require('gulp-minify');
var plumber = require('gulp-plumber');
var istanbul = require('gulp-istanbul');
var mocha = require('gulp-mocha');
var watch = require('gulp-watch');
gulp.task(
'build',
function() {
return gulp.src('./src/game-lib-*.js')
.pipe(sort())
.pipe(concat('game-lib.js'))
.pipe(minify({
ext:{
src:'.js',
min:'-min.js'
}
}))
.pipe(gulp.dest('./build/'));
}
);
gulp.task('test-prepare', function(){
return gulp.src('./build/game-lib.js')
.pipe(plumber())
.pipe(istanbul())
.pipe(istanbul.hookRequire())
.on('end', function(){
console.log('prepared the game lib for code coverage');
});
});
gulp.task(
'test',
['build', 'test-prepare'],
function() {
gulp.src('./test/test.*.js')
.pipe(sort())
.pipe(plumber())
.pipe(mocha({reporter: 'spec'}))
.pipe(istanbul.writeReports({
dir: './build/coverage'
}))
.pipe(istanbul.enforceThresholds({thresholds:{global:1}}))
.on('error',
function(error) {
console.log('plugin error occurred' + error);
}
)
.on('end',
function() {
console.log('test task ended')
}
);
}
);
gulp.task(
'default',
[
'build'
],
function() {
return watch([
'src/*.js'
],
function() {
gulp.start([
'build'
]);
})
}
);

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "gamewheel-game-lib",
"description": "Gamewheel Game Library",
"version": "0.0.1",
"dependencies": {
"cannon": "^0.6.2",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.0",
"gulp-minify": "0.0.14",
"gulp-sort": "^2.0.0",
"three": "^0.81.2"
},
"repository": "https://github.com/ToywheelDev/game-lib.git",
"license": "UNLICENSED",
"devDependencies": {
"chai": "^3.5.0",
"gulp-istanbul": "^1.1.1",
"gulp-mocha": "^3.0.1",
"gulp-plumber": "^1.1.0",
"gulp-watch": "^4.3.10",
"sinon": "^1.17.6",
"sinon-chai": "^2.8.0"
}
}

16
src/game-lib-a.js Normal file
View File

@ -0,0 +1,16 @@
if (typeof GameLib == 'undefined') {
function GameLib() {}
}
if (typeof GameLib.D3 == 'undefined') {
GameLib.D3 = function(){};
}
if (typeof Q == 'undefined') {
if (typeof require == 'undefined') {
console.warn('You need the Q promise library for the GameLib.D3');
throw new Error('You need the Q promise library for the GameLib.D3');
}
var Q = require('q');
}

View File

@ -0,0 +1,13 @@
/**
* BoneWeight object - associates a vertex to a bone with some weight
* @param boneIndex int
* @param weight float
* @constructor
*/
GameLib.D3.BoneWeight = function(
boneIndex,
weight
) {
this.boneIndex = boneIndex;
this.weight = weight;
};

65
src/game-lib-bone.js Normal file
View File

@ -0,0 +1,65 @@
/**
* Bone Superset
* @param id
* @param name string
* @param boneId
* @param childBoneIds
* @param parentBoneId
* @param quaternion
* @param position
* @param rotation
* @param scale GameLib.D3.Vector3
* @param up
* @constructor
*/
GameLib.D3.Bone = function(
id,
boneId,
name,
childBoneIds,
parentBoneId,
quaternion,
position,
rotation,
scale,
up
) {
this.id = id;
this.name = name;
this.boneId = boneId;
if (typeof childBoneIds == 'undefined') {
childBoneIds = [];
}
this.childBoneIds = childBoneIds;
if (typeof parentBoneId == 'undefined') {
parentBoneId = null;
}
this.parentBoneId = parentBoneId;
if (typeof quaternion == 'undefined') {
quaternion = new GameLib.D3.Vector4();
}
this.quaternion = quaternion;
if (typeof position == 'undefined') {
position = new GameLib.D3.Vector3(0,0,0);
}
this.position = position;
if (typeof rotation == 'undefined') {
rotation = new GameLib.D3.Vector3(0,0,0);
}
this.rotation = rotation;
if (typeof scale == 'undefined') {
scale = new GameLib.D3.Vector3(1,1,1);
}
this.scale = scale;
if (typeof up == 'undefined') {
up = new GameLib.D3.Vector3(0,1,0);
}
this.up = up;
};

View File

@ -0,0 +1,77 @@
/**
* Physics Broadphase Superset
* @param id
* @param name String
* @param broadphaseType Number
* @param engine GameLib.D3.Engine
* @param createInstance Boolean
* @constructor
*/
GameLib.D3.Broadphase = function(
id,
name,
broadphaseType,
engine,
createInstance
) {
this.id = id;
if (typeof name == 'undefined') {
name = 'broadphase-' + broadphaseType;
}
this.name = name;
if (typeof broadphaseType == 'undefined') {
broadphaseType = GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE;
}
this.broadphaseType = broadphaseType;
if (typeof engine == 'undefined') {
engine = null;
}
this.engine = engine;
this.instance = null;
if (createInstance) {
this.createInstance();
}
};
/**
* Creates a custom Broadphase instance based on the engine type
*/
GameLib.D3.Broadphase.prototype.createInstance = function() {
if (!(this.engine instanceof GameLib.D3.Engine)) {
console.warn('No Engine');
throw new Error('No Engine');
}
this.engine.isNotCannonThrow();
var instance = null;
if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) {
instance = new this.engine.instance.NaiveBroadphase();
} else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) {
instance = new this.engine.instance.GridBroadphase();
} else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) {
instance = new this.engine.instance.SAPBroardphase();
} else {
console.warn('Unsupported broadphase type: ' + this.broadphaseType);
throw new Error('Unsupported broadphase type: ' + this.broadphaseType);
}
this.instance = instance;
return instance;
};
/**
* Broadphase Types
* @type {number}
*/
GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE = 0x1;
GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID = 0x2;
GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP = 0x3;

14
src/game-lib-color.js Normal file
View File

@ -0,0 +1,14 @@
/**
* Color Superset
* @param r
* @param g
* @param b
* @param a
* @constructor
*/
GameLib.D3.Color = function(r, g, b, a) {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
};

55
src/game-lib-engine.js Normal file
View File

@ -0,0 +1,55 @@
/**
* Engine Superset
* @param engineType
* @param instance {CANNON | Ammo | Goblin}
* @constructor
*/
GameLib.D3.Engine = function(
engineType,
instance
) {
this.engineType = engineType;
this.instance = instance;
};
/**
* True if CANNON physics
* @returns {boolean}
*/
GameLib.D3.Engine.prototype.isCannon = function() {
return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_CANNON)
};
/**
* Logs a warning and throws an error if not cannon
*/
GameLib.D3.Engine.prototype.isNotCannonThrow = function() {
if (this.engineType != GameLib.D3.Engine.ENGINE_TYPE_CANNON) {
console.warn('Only CANNON supported for this function');
throw new Error('Only CANNON supported for this function');
}
};
/**
* True if Ammo physics
* @returns {boolean}
*/
GameLib.D3.Engine.prototype.isAmmo = function() {
return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_AMMO)
};
/**
* True if Goblin physics
* @returns {boolean}
*/
GameLib.D3.Engine.prototype.isGoblin = function() {
return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_GOBLIN)
};
/**
* Physics GameLib.D3.Engine Types
* @type {number}
*/
GameLib.D3.Engine.ENGINE_TYPE_CANNON = 0x1;
GameLib.D3.Engine.ENGINE_TYPE_AMMO = 0x2;
GameLib.D3.Engine.ENGINE_TYPE_GOBLIN = 0x3;

View File

@ -0,0 +1,237 @@
/**
* Fly Controls
* @param camera
* @param THREE
* @param canvas
* @constructor
*/
GameLib.D3.FlyControls = function(
camera,
THREE,
canvas
) {
this.flySpeed = 100;
this.canvas = canvas;
this.THREE = THREE;
this.yaw = 0;
this.pitch = 0;
this.canRotate = false;
this.moveForward = false;
this.moveBackward = false;
this.moveLeft = false;
this.moveRight = false;
this.moveUp = false;
this.moveDown = false;
this.mouseUpCallback = this.onMouseUp.bind(this);
this.mouseDownCallback = this.onMouseDown.bind(this);
this.mouseMoveCallback = this.onMouseMove.bind(this);
this.mouseWheelCallback = this.onMouseWheel.bind(this);
this.keyDownCallback = this.onKeyDown.bind(this);
this.keyUpCallback = this.onKeyUp.bind(this);
this.camera = camera;
this.canvas.addEventListener('keydown', this.keyDownCallback, false);
this.canvas.addEventListener('keyup', this.keyUpCallback, false);
this.canvas.addEventListener('mousedown', this.mouseDownCallback, false);
this.canvas.addEventListener('mouseup', this.mouseUpCallback, false);
this.canvas.addEventListener('mousewheel', this.mouseWheelCallback, false);
this.havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
this.element = document.body;
if (this.havePointerLock) {
this.element.requestPointerLock = this.element.requestPointerLock || this.element.mozRequestPointerLock || this.element.webkitRequestPointerLock;
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock || document.webkitExitPointerLock;
}
};
/**
* Go forward / backward on mouse wheel
* @param event
*/
GameLib.D3.FlyControls.prototype.onMouseWheel = function(event) {
this.moveForward = true;
this.applyTranslation(event.wheelDelta * 0.001);
event.preventDefault();
this.moveForward = false;
};
/**
* Start rotating the camera on mouse middle button down
* @param event
*/
GameLib.D3.FlyControls.prototype.onMouseDown = function(event) {
if (event.button == 1) {
this.canRotate = true;
this.canvas.addEventListener('mousemove', this.mouseMoveCallback, false);
}
};
/**
* Stop rotating on middle mouse button down
* @param event
*/
GameLib.D3.FlyControls.prototype.onMouseUp = function(event) {
if (event.button == 1) {
this.canRotate = false;
this.canvas.removeEventListener('mousemove', this.mouseMoveCallback);
}
};
/**
* Apply current yaw and pitch to camera
*/
GameLib.D3.FlyControls.prototype.applyRotation = function() {
this.camera.rotation.set(this.pitch, this.yaw, 0, "YXZ");
};
/**
* Apply current position to camera
* @param deltaTime
*/
GameLib.D3.FlyControls.prototype.applyTranslation = function(deltaTime) {
var direction = new this.THREE.Vector3(0, 0, -1);
var rotation = new this.THREE.Euler(0, 0, 0, "YXZ");
rotation.set(this.pitch, this.yaw, 0, "YXZ");
direction = direction.applyEuler(rotation);
var forward = direction.normalize();
var right = forward.cross(new this.THREE.Vector3(0, 1, 0));
if(this.moveForward) {
this.camera.position.x += forward.x * (deltaTime * this.flySpeed);
this.camera.position.y += forward.y * (deltaTime * this.flySpeed);
this.camera.position.z += forward.z * (deltaTime * this.flySpeed);
} else if(this.moveBackward) {
this.camera.position.x -= forward.x * (deltaTime * this.flySpeed);
this.camera.position.y -= forward.y * (deltaTime * this.flySpeed);
this.camera.position.z -= forward.z * (deltaTime * this.flySpeed);
}
if(this.moveLeft) {
this.camera.position.x -= right.x * (deltaTime * this.flySpeed);
this.camera.position.y -= right.y * (deltaTime * this.flySpeed);
this.camera.position.z -= right.z * (deltaTime * this.flySpeed);
} else if(this.moveRight) {
this.camera.position.x += right.x * (deltaTime * this.flySpeed);
this.camera.position.y += right.y * (deltaTime * this.flySpeed);
this.camera.position.z += right.z * (deltaTime * this.flySpeed);
}
if(this.moveUp) {
this.camera.position.y += (deltaTime * this.flySpeed);
} else if(this.moveDown) {
this.camera.position.y -= (deltaTime * this.flySpeed);
}
};
/**
* This update function should be called from the animation function in order to apply the 'frame rate independent'
* movement to the camera
* @param deltaTime
*/
GameLib.D3.FlyControls.prototype.update = function(deltaTime) {
this.applyRotation();
this.applyTranslation(deltaTime);
};
/**
* Rotate on mouse move
* @param event
*/
GameLib.D3.FlyControls.prototype.onMouseMove = function ( event ) {
if (this.canRotate) {
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
this.yaw -= movementX * 0.002;
this.pitch -= movementY * 0.002;
}
};
/**
* Keyboard controls
* @param event
*/
GameLib.D3.FlyControls.prototype.onKeyDown = function ( event ) {
switch ( event.keyCode ) {
case 87: // w
this.moveForward = true;
break;
case 65: // a
this.moveLeft = true;
break;
case 83: // s
this.moveBackward = true;
break;
case 68: // d
this.moveRight = true;
break;
case 104: // keypad up arrow
this.moveUp = true;
break;
case 98: // keypad down arrow
this.moveDown = true;
break;
}
};
/**
* Keyboard controls
* @param event
*/
GameLib.D3.FlyControls.prototype.onKeyUp = function ( event ) {
switch ( event.keyCode ) {
case 38: // up
case 87: // w
this.moveForward = false;
break;
case 37: // left
case 65: // a
this.moveLeft = false;
break;
case 40: // down
case 83: // s
this.moveBackward = false;
break;
case 39: // right
case 68: // d
this.moveRight = false;
break;
case 104: // keypad up arrow
this.moveUp = false;
break;
case 98: // keypad down arrow
this.moveDown = false;
break;
}
};

106
src/game-lib-game.js Normal file
View File

@ -0,0 +1,106 @@
GameLib.D3.Game = function (
) {
this.scenes = {};
this.physicsWorlds = [];
this.sceneToPhysicsWorldsMap = {};
};
GameLib.D3.Game.prototype.AddScene = function(
scene
) {
this.scenes[scene.name] = scene;
};
GameLib.D3.Game.prototype.AddPhysicsWorld = function(
physicsWorld
) {
this.physicsWorlds.push(physicsWorld);
};
GameLib.D3.Game.prototype.LinkPhysicsWorldToScene = function(
physicsWorld,
scene
) {
this.sceneToPhysicsWorldsMap[scene.name] = this.sceneToPhysicsWorldsMap[scene.name] || [];
this.sceneToPhysicsWorldsMap[scene.name].push(physicsWorld);
};
GameLib.D3.Game.prototype.GetPhysicsWorldsForScene = function (
scene
) {
return this.sceneToPhysicsWorldsMap[scene.name];
};
GameLib.D3.Game.prototype.ProcessPhysics = function (
timestep
) {
for(var s in this.sceneToPhysicsWorldsMap) {
var physicsWorldArray = this.sceneToPhysicsWorldsMap[s];
var scene = this.scenes[s];
if(scene && physicsWorldArray) {
for(var i = 0, l = physicsWorldArray.length; i < l; i++) {
var physicsWorld = physicsWorldArray[i];
physicsWorld.Step(timestep);
for(var p in physicsWorld.linkedPairs) {
var pair = physicsWorld.linkedPairs[p];
var mesh = pair.threeMesh;
var body = pair.physicsBody;
if(mesh) {
if(physicsWorld.engineType === GameLib.D3.Physics.TYPE_CANNON) {
var quaternion = new THREE.Quaternion();
quaternion.copy(body.rigidBodyInstance.quaternion);
var quaternionCopy = quaternion.clone();
var position = new THREE.Vector3();
position.copy(body.rigidBodyInstance.position);
if(mesh.permutate) {
if(mesh.permutate.offset) {
if(mesh.permutate.offset.quaternion) {
var offsetQuaternion = new THREE.Quaternion();
offsetQuaternion.copy(mesh.permutate.offset.quaternion);
quaternion = quaternion.multiply(offsetQuaternion).normalize();
}
if(mesh.permutate.offset.position) {
var offsetPosition = new THREE.Vector3();
offsetPosition.copy(mesh.permutate.offset.position);
//position = position.add(offsetPosition);
position = position.add(offsetPosition.applyQuaternion(quaternionCopy));
}
}
}
mesh.position.copy(position);
mesh.quaternion.copy(quaternion);
}
}
}
}
}
}
};
GameLib.D3.Game.prototype.LinkPair = function (
threeMesh,
physicsBody,
physicsWorld
) {
physicsWorld.linkedPairs = physicsWorld.linkedPairs || [];
physicsWorld.linkedPairs.push({
threeMesh : threeMesh,
physicsBody : physicsBody
});
};

37
src/game-lib-graphics.js Normal file
View File

@ -0,0 +1,37 @@
/**
* Graphics Superset
* @param graphicsType
* @param instance {THREE}
* @constructor
*/
GameLib.D3.Graphics = function(
graphicsType,
instance
) {
this.graphicsType = graphicsType;
this.instance = instance;
};
/**
* True if THREE physics
* @returns {boolean}
*/
GameLib.D3.Graphics.prototype.isThree = function() {
return (this.graphicsType == GameLib.D3.Graphics.GRAPHICS_TYPE_THREE)
};
/**
* Logs a warning and throws an error if not cannon
*/
GameLib.D3.Graphics.prototype.isNotThreeThrow = function() {
if (this.graphicsType != GameLib.D3.Graphics.GRAPHICS_TYPE_THREE) {
console.warn('Only THREE supported for this function');
throw new Error('Only THREE supported for this function');
}
};
/**
* Physics GameLib.D3.Graphics Types
* @type {number}
*/
GameLib.D3.Graphics.GRAPHICS_TYPE_THREE = 0x1;

110
src/game-lib-heightmap.js Normal file
View File

@ -0,0 +1,110 @@
/**
*
* @param sizeX Number
* @param sizeY Number
* @param matrix matrix 2D Array with height data (Column Major)
* @constructor
*/
GameLib.D3.Heightmap = function(
sizeX,
sizeY,
matrix
) {
if (typeof sizeX == 'undefined') {
sizeX = 0;
}
this.sizeX = sizeX;
if (typeof sizeY == 'undefined') {
sizeY = 0;
}
this.sizeY = sizeY;
if (typeof matrix == 'undefined') {
matrix = [];
}
this.matrix = matrix;
};
GameLib.D3.Heightmap.prototype.generateThreeMeshFromHeightField = function(
THREE,
heightFieldShape,
engine
) {
var geometry = new THREE.Geometry();
var v0 = new this.physics.CANNON.Vec3();
var v1 = new this.physics.CANNON.Vec3();
var v2 = new this.physics.CANNON.Vec3();
var shape = heightFieldShape;
for (var xi = 0; xi < shape.data.length - 1; xi++) {
for (var yi = 0; yi < shape.data[xi].length - 1; yi++) {
for (var k = 0; k < 2; k++) {
shape.getConvexTrianglePillar(xi, yi, k===0);
v0.copy(shape.pillarConvex.vertices[0]);
v1.copy(shape.pillarConvex.vertices[1]);
v2.copy(shape.pillarConvex.vertices[2]);
v0.vadd(shape.pillarOffset, v0);
v1.vadd(shape.pillarOffset, v1);
v2.vadd(shape.pillarOffset, v2);
geometry.vertices.push(
new THREE.Vector3(v0.x, v0.y, v0.z),
new THREE.Vector3(v1.x, v1.y, v1.z),
new THREE.Vector3(v2.x, v2.y, v2.z)
);
var i = geometry.vertices.length - 3;
geometry.faces.push(new THREE.Face3(i, i+1, i+2));
}
}
}
geometry.computeBoundingSphere();
geometry.computeFaceNormals();
return new THREE.Mesh(geometry, new THREE.MeshNormalMaterial({ wireframe : false, shading : THREE.SmoothShading }));
};
GameLib.D3.Heightmap.prototype.generateHeightmapDataFromImage = function (
imagePath,
callback // receives HeightmapData instance as the first argument
) {
var img = new Image();
img.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
var imgd = context.getImageData(0, 0, img.width, img.height);
var pixels = imgd.data;
var heightList = [];
for (var i = 0, n = pixels.length; i < n; i += (4)) {
heightList.push(pixels[i]);
}
var matrix = [];
var sizeX = img.width,
sizeY = img.height;
for (var i = 0; i < sizeX; i++) {
matrix.push([]);
for (var j = 0; j < sizeY; j++) {
var height = (heightList[(sizeX - i) + j * sizeY] / 255) * 15;
matrix[i].push(height);
}
}
// todo: delete canvas here
callback(new GameLib.D3.HeightmapData(sizeX, sizeY, matrix));
};
img.src = imagePath;
};

45
src/game-lib-image.js Normal file
View File

@ -0,0 +1,45 @@
/**
* Image
* @param id
* @param textureLink
* @param filename
* @param size
* @param contentType
* @constructor
*/
GameLib.D3.Image = function(
id,
textureLink,
filename,
size,
contentType
) {
this.id = id;
this.filename = filename;
this.textureLink = textureLink;
if (typeof size == 'undefined') {
size = 0;
}
this.size = size;
if (typeof contentType == 'undefined') {
contentType = 'application/octet-stream';
if (this.filename.match(/(png)$/i)) {
contentType = 'image/png';
}
if (this.filename.match(/(jpg|jpeg)$/i)) {
contentType = 'image/jpeg';
}
if (this.filename.match(/(gif)$/i)) {
contentType = 'image/gif';
}
}
this.contentType = contentType;
};

92
src/game-lib-light.js Normal file
View File

@ -0,0 +1,92 @@
/**
* Light Superset
* @param id
* @param lightType
* @param name
* @param color
* @param intensity
* @param position
* @param targetPosition
* @param quaternion
* @param rotation
* @param scale
* @param distance
* @param decay
* @param power
* @param angle
* @param penumbra
* @constructor
*/
GameLib.D3.Light = function(
id,
lightType,
name,
color,
intensity,
position,
targetPosition,
quaternion,
rotation,
scale,
distance,
decay,
power,
angle,
penumbra
) {
this.id = id;
this.lightType = lightType;
this.name = name;
this.color = color;
this.intensity = intensity;
if (typeof position == 'undefined') {
position = new GameLib.D3.Vector3(0,0,0);
}
this.position = position;
if (typeof targetPosition == 'undefined') {
targetPosition = new GameLib.D3.Vector3(0,0,0);
}
this.targetPosition = targetPosition;
if (typeof quaternion == 'undefined'){
quaternion = new GameLib.D3.Vector4();
}
this.quaternion = quaternion;
if (typeof rotation == 'undefined'){
rotation = new GameLib.D3.Vector3(0,0,0);
}
this.rotation = rotation;
if (typeof scale == 'undefined'){
scale = new GameLib.D3.Vector3(1,1,1);
}
this.scale = scale;
if (typeof distance == 'undefined'){
distance = 0;
}
this.distance = distance;
if (typeof decay == 'undefined'){
decay = 1;
}
this.decay = decay;
if (typeof power == 'undefined'){
power = 4 * Math.PI;
}
this.power = power;
if (typeof angle == 'undefined'){
angle = Math.PI / 3;
}
this.angle = angle;
if (typeof penumbra == 'undefined'){
penumbra = 0;
}
this.penumbra = penumbra;
};

694
src/game-lib-material.js Normal file
View File

@ -0,0 +1,694 @@
/**
* Material Superset
* @param id
* @param name
* @param materialType
* @param opacity
* @param side
* @param transparent
* @param maps
* @param specular
* @param lightMapIntensity
* @param aoMapIntensity
* @param color
* @param emissive
* @param emissiveIntensity
* @param combine
* @param shininess
* @param reflectivity
* @param refractionRatio
* @param fog
* @param wireframe
* @param wireframeLineWidth
* @param wireframeLineCap
* @param wireframeLineJoin
* @param vertexColors
* @param skinning
* @param morphTargets
* @param morphNormals
* @param lineWidth
* @param lineCap
* @param lineJoin
* @param dashSize
* @param gapWidth
* @param blending
* @param blendSrc
* @param blendDst
* @param blendEquation
* @param depthTest
* @param depthFunc
* @param depthWrite
* @param polygonOffset
* @param polygonOffsetFactor
* @param polygonOffsetUnits
* @param alphaTest
* @param clippingPlanes
* @param clipShadows
* @param visible
* @param overdraw
* @param shading
* @param bumpScale
* @param normalScale
* @param displacementScale
* @param displacementBias
* @param roughness
* @param metalness
* @param pointSize
* @param pointSizeAttenuation
* @param spriteRotation
* @param envMapIntensity
* @constructor
*/
GameLib.D3.Material = function(
id,
name,
materialType,
opacity,
side,
transparent,
maps,
specular,
lightMapIntensity,
aoMapIntensity,
color,
emissive,
emissiveIntensity,
combine,
shininess,
reflectivity,
refractionRatio,
fog,
wireframe,
wireframeLineWidth,
wireframeLineCap,
wireframeLineJoin,
vertexColors,
skinning,
morphTargets,
morphNormals,
lineWidth,
lineCap,
lineJoin,
dashSize,
gapWidth,
blending,
blendSrc,
blendDst,
blendEquation,
depthTest,
depthFunc,
depthWrite,
polygonOffset,
polygonOffsetFactor,
polygonOffsetUnits,
alphaTest,
clippingPlanes,
clipShadows,
visible,
overdraw,
shading,
bumpScale,
normalScale,
displacementScale,
displacementBias,
roughness,
metalness,
pointSize,
pointSizeAttenuation,
spriteRotation,
envMapIntensity
) {
this.id = id;
this.name = name;
if (typeof materialType == 'undefined') {
materialType = GameLib.D3.Material.TYPE_MESH_STANDARD;
}
this.materialType = materialType;
if (typeof opacity == 'undefined') {
opacity = 1.0;
}
this.opacity = opacity;
if (typeof side == 'undefined') {
side = GameLib.D3.Material.TYPE_FRONT_SIDE;
}
this.side = side;
if (typeof transparent == 'undefined') {
transparent = false;
}
this.transparent = transparent;
if (typeof maps == 'undefined') {
maps = {
alpha: null,
ao: null,
bump: null,
diffuse: null,
displacement: null,
emissive: null,
environment: null,
light: null,
metalness: null,
normal: null,
roughness: null,
specular: null
};
}
this.maps = maps;
if (typeof specular == 'undefined') {
specular = new GameLib.D3.Color(0.06, 0.06, 0.06, 0.06);
}
this.specular = specular;
if (typeof lightMapIntensity == 'undefined') {
lightMapIntensity = 1;
}
this.lightMapIntensity = lightMapIntensity;
if (typeof aoMapIntensity == 'undefined') {
aoMapIntensity = 1;
}
this.aoMapIntensity = aoMapIntensity;
if (typeof color == 'undefined') {
color = new GameLib.D3.Color(1, 1, 1, 1)
}
this.color = color;
if (typeof emissive == 'undefined') {
emissive = new GameLib.D3.Color(0, 0, 0, 0);
}
this.emissive = emissive;
if (typeof emissiveIntensity == 'undefined') {
emissiveIntensity = 1;
}
this.emissiveIntensity = emissiveIntensity;
if (typeof combine == 'undefined') {
combine = GameLib.D3.Material.TYPE_MULTIPLY_OPERATION;
}
this.combine = combine;
if (typeof shininess == 'undefined') {
shininess = 30;
}
this.shininess = shininess;
if (typeof reflectivity == 'undefined') {
reflectivity = 1;
}
this.reflectivity = reflectivity;
if (typeof refractionRatio == 'undefined') {
refractionRatio = 0.98;
}
this.refractionRatio = refractionRatio;
if (typeof fog == 'undefined') {
fog = true;
}
this.fog = fog;
if (typeof wireframe == 'undefined') {
wireframe = false;
}
this.wireframe = wireframe;
if (typeof wireframeLineWidth == 'undefined') {
wireframeLineWidth = 1;
}
this.wireframeLineWidth = wireframeLineWidth;
if (typeof wireframeLineCap == 'undefined') {
wireframeLineCap = 'round';
}
this.wireframeLineCap = wireframeLineCap;
if (typeof wireframeLineJoin == 'undefined') {
wireframeLineJoin = 'round';
}
this.wireframeLineJoin = wireframeLineJoin;
if (typeof vertexColors == 'undefined') {
vertexColors = GameLib.D3.Material.TYPE_NO_COLORS;
}
this.vertexColors = vertexColors;
if (typeof skinning == 'undefined') {
skinning = false;
}
this.skinning = skinning;
if (typeof morphTargets == 'undefined') {
morphTargets = false;
}
this.morphTargets = morphTargets;
if (typeof morphNormals == 'undefined') {
morphNormals = false;
}
this.morphNormals = morphNormals;
if (typeof overdraw == 'undefined') {
overdraw = 0;
}
this.overdraw = overdraw;
if (typeof lineWidth == 'undefined') {
lineWidth = 1;
}
this.lineWidth = lineWidth;
if (typeof lineCap == 'undefined') {
lineCap = 'round';
}
this.lineCap = lineCap;
if (typeof lineJoin == 'undefined') {
lineJoin = 'round';
}
this.lineJoin = lineJoin;
if (typeof dashSize == 'undefined') {
dashSize = 3;
}
this.dashSize = dashSize;
if (typeof gapWidth == 'undefined') {
gapWidth = 1;
}
this.gapWidth = gapWidth;
if (typeof blending == 'undefined') {
blending = GameLib.D3.Material.TYPE_NORMAL_BLENDING;
}
this.blending = blending;
if (typeof blendSrc == 'undefined') {
blendSrc = GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR;
}
this.blendSrc = blendSrc;
if (typeof blendDst == 'undefined') {
blendDst = GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR;
}
this.blendDst = blendDst;
if (typeof blendEquation == 'undefined') {
blendEquation = GameLib.D3.Material.TYPE_ADD_EQUATION;
}
this.blendEquation = blendEquation;
if (typeof depthTest == 'undefined') {
depthTest = true;
}
this.depthTest = depthTest;
if (typeof depthFunc == 'undefined') {
depthFunc = GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH;
}
this.depthFunc = depthFunc;
if (typeof depthWrite == 'undefined') {
depthWrite = true;
}
this.depthWrite = depthWrite;
if (typeof polygonOffset == 'undefined') {
polygonOffset = false;
}
this.polygonOffset = polygonOffset;
if (typeof polygonOffsetFactor == 'undefined') {
polygonOffsetFactor = 1;
}
this.polygonOffsetFactor = polygonOffsetFactor;
if (typeof polygonOffsetUnits == 'undefined') {
polygonOffsetUnits = 1;
}
this.polygonOffsetUnits = polygonOffsetUnits;
if (typeof alphaTest == 'undefined') {
alphaTest = 0;
}
this.alphaTest = alphaTest;
if (typeof clippingPlanes == 'undefined') {
clippingPlanes = [];
}
this.clippingPlanes = clippingPlanes;
if (typeof clipShadows == 'undefined') {
clipShadows = false;
}
this.clipShadows = clipShadows;
if (typeof visible == 'undefined') {
visible = true;
}
this.visible = visible;
if (typeof shading == 'undefined') {
shading = GameLib.D3.Material.TYPE_FLAT_SHADING;
}
this.shading = shading;
if (typeof bumpScale == 'undefined') {
bumpScale = 1;
}
this.bumpScale = bumpScale;
if (typeof normalScale == 'undefined') {
normalScale = 1;
}
this.normalScale = normalScale;
if (typeof displacementScale == 'undefined') {
displacementScale = 1;
}
this.displacementScale = displacementScale;
if (typeof displacementBias == 'undefined') {
displacementBias = 0;
}
this.displacementBias = displacementBias;
if (typeof roughness == 'undefined') {
roughness = 0.5;
}
this.roughness = roughness;
if (typeof metalness == 'undefined') {
metalness = 0.5;
}
this.metalness = metalness;
if (typeof pointSize == 'undefined') {
pointSize = 1;
}
this.pointSize = pointSize;
if (typeof pointSizeAttenuation == 'undefined') {
pointSizeAttenuation = true;
}
this.pointSizeAttenuation = pointSizeAttenuation;
if (typeof spriteRotation == 'undefined') {
spriteRotation = 0;
}
this.spriteRotation = spriteRotation;
if (typeof envMapIntensity == 'undefined') {
envMapIntensity = 1.0;
}
this.envMapIntensity = envMapIntensity;
};
/**
* Combine Method
* @type {number}
*/
GameLib.D3.Material.TYPE_MULTIPLY_OPERATION = 0;
GameLib.D3.Material.TYPE_MIX_OPERATION = 1;
GameLib.D3.Material.TYPE_ADD_OPERATION = 2;
/**
* Vertex Color Mode
* @type {number}
*/
GameLib.D3.Material.TYPE_NO_COLORS = 0;
GameLib.D3.Material.TYPE_FACE_COLORS = 1;
GameLib.D3.Material.TYPE_VERTEX_COLORS = 2;
/**
* Blending Mode
* @type {number}
*/
GameLib.D3.Material.TYPE_NORMAL_BLENDING = 1;
GameLib.D3.Material.TYPE_ADDITIVE_BLENDING = 2;
GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING = 3;
GameLib.D3.Material.TYPE_MULTIPLY_BLENDING = 4;
GameLib.D3.Material.TYPE_CUSTOM_BLENDING = 5;
/**
* Blend Source and Destination
* @type {number}
*/
GameLib.D3.Material.TYPE_ZERO_FACTOR = 200;
GameLib.D3.Material.TYPE_ONE_FACTOR = 201;
GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR = 202;
GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR = 203;
GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR = 204;
GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR = 205;
GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR = 206;
GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR = 207;
GameLib.D3.Material.TYPE_DST_COLOR_FACTOR = 208;
GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR = 209;
GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR = 210;
/**
* Blend Operation
* @type {number}
*/
GameLib.D3.Material.TYPE_ADD_EQUATION = 100;
GameLib.D3.Material.TYPE_SUBTRACT_EQUATION = 101;
GameLib.D3.Material.TYPE_REVERSE_SUBTRACT_EQUATION = 102;
GameLib.D3.Material.TYPE_MIN_EQUATION = 103;
GameLib.D3.Material.TYPE_MAX_EQUATION = 104;
/**
* Depth Function
* @type {number}
*/
GameLib.D3.Material.TYPE_NEVER_DEPTH = 0;
GameLib.D3.Material.TYPE_ALWAYS_DEPTH = 1;
GameLib.D3.Material.TYPE_LESS_DEPTH = 2;
GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH = 3;
GameLib.D3.Material.TYPE_EQUAL_DEPTH = 4;
GameLib.D3.Material.TYPE_GREATER_EQUAL_DEPTH = 5;
GameLib.D3.Material.TYPE_GREATER_DEPTH = 6;
GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH = 7;
/**
* Culling Mode
* @type {number}
*/
GameLib.D3.Material.TYPE_FRONT_SIDE = 0;
GameLib.D3.Material.TYPE_BACK_SIDE = 1;
GameLib.D3.Material.TYPE_DOUBLE_SIDE = 2;
/**
* Shading Type
* @type {number}
*/
GameLib.D3.Material.TYPE_FLAT_SHADING = 1;
GameLib.D3.Material.TYPE_SMOOTH_SHADING = 2;
/**
* Material Type
* @type {string}
*/
GameLib.D3.Material.TYPE_LINE_BASIC = "LineBasicMaterial";
GameLib.D3.Material.TYPE_LINE_DASHED = "LineDashedMaterial";
GameLib.D3.Material.TYPE_MESH_BASIC = "MeshBasicMaterial";
GameLib.D3.Material.TYPE_MESH_DEPTH = "MeshDepthMaterial";
GameLib.D3.Material.TYPE_MESH_LAMBERT = "MeshLambertMaterial";
GameLib.D3.Material.TYPE_MESH_NORMAL = "MeshNormalMaterial";
GameLib.D3.Material.TYPE_MESH_PHONG = "MeshPhongMaterial";
GameLib.D3.Material.TYPE_MESH_STANDARD = "MeshStandardMaterial";
GameLib.D3.Material.TYPE_POINTS = "PointsMaterial";
GameLib.D3.Material.TYPE_SPRITE = "SpriteMaterial";
GameLib.D3.Material.TYPE_MULTI_MATERIAL= "MultiMaterial";
/**
* Creates an instance Material from a GameLib.D3.Material
* @param gameLibMaterial GameLib.D3.Material
* @param graphics GameLib.D3.Graphics
* @param uploadUrl String
* @param progressCallback
*/
GameLib.D3.Material.createInstanceMaterial = function(
gameLibMaterial,
graphics,
uploadUrl,
progressCallback
) {
var defer = Q.defer();
var instanceMaterial = null;
var blenderMaps = [];
if (gameLibMaterial.materialType == GameLib.D3.Material.TYPE_MESH_STANDARD) {
instanceMaterial = new graphics.instance.MeshStandardMaterial({
name: gameLibMaterial.name,
opacity: gameLibMaterial.opacity,
transparent: gameLibMaterial.transparent,
blending: gameLibMaterial.blending,
blendSrc: gameLibMaterial.blendSrc,
blendDst: gameLibMaterial.blendDst,
blendEquation: gameLibMaterial.blendEquation,
depthTest: gameLibMaterial.depthTest,
depthFunc: gameLibMaterial.depthFunc,
depthWrite: gameLibMaterial.depthWrite,
polygonOffset: gameLibMaterial.polygonOffset,
polygonOffsetFactor: gameLibMaterial.polygonOffsetFactor,
polygonOffsetUnits: gameLibMaterial.polygonOffsetUnits,
alphaTest: gameLibMaterial.alphaTest,
clippingPlanes: gameLibMaterial.clippingPlanes,
clipShadows: gameLibMaterial.clipShadows,
overdraw: gameLibMaterial.overdraw,
visible: gameLibMaterial.visible,
side: gameLibMaterial.side,
color: new graphics.instance.Color(
gameLibMaterial.color.r,
gameLibMaterial.color.g,
gameLibMaterial.color.b
),
roughness: gameLibMaterial.roughness,
metalness: gameLibMaterial.metalness,
lightMapIntensity: gameLibMaterial.lightMapIntensity,
aoMapIntensity: gameLibMaterial.aoMapIntensity,
emissive: new graphics.instance.Color(
gameLibMaterial.emissive.r,
gameLibMaterial.emissive.g,
gameLibMaterial.emissive.b
),
emissiveIntensity: gameLibMaterial.emissiveIntensity,
bumpScale: gameLibMaterial.bumpScale,
normalScale: gameLibMaterial.normalScale,
displacementScale: gameLibMaterial.displacementScale,
refractionRatio: gameLibMaterial.refractionRatio,
fog: gameLibMaterial.fog,
shading: gameLibMaterial.shading,
wireframe: gameLibMaterial.wireframe,
wireframeLinewidth: gameLibMaterial.wireframeLineWidth,
wireframeLinecap: gameLibMaterial.wireframeLineCap,
wireframeLinejoin: gameLibMaterial.wireframeLineJoin,
vertexColors: gameLibMaterial.vertexColors,
skinning: gameLibMaterial.skinning,
morphTargets: gameLibMaterial.morphTargets,
morphNormals: gameLibMaterial.morphNormals
});
blenderMaps.push(
'diffuse',
'light',
'ao',
'emissive',
'bump',
'normal',
'displacement',
'roughness',
'metalness',
'alpha',
'environment'
);
} else if (gameLibMaterial.materialType == GameLib.D3.Material.TYPE_MESH_PHONG) {
instanceMaterial = new graphics.instance.MeshPhongMaterial({
name: gameLibMaterial.name,
opacity: gameLibMaterial.opacity,
transparent: gameLibMaterial.transparent,
blending: gameLibMaterial.blending,
blendSrc: gameLibMaterial.blendSrc,
blendDst: gameLibMaterial.blendDst,
blendEquation: gameLibMaterial.blendEquation,
depthTest: gameLibMaterial.depthTest,
depthFunc: gameLibMaterial.depthFunc,
depthWrite: gameLibMaterial.depthWrite,
polygonOffset: gameLibMaterial.polygonOffset,
polygonOffsetFactor: gameLibMaterial.polygonOffsetFactor,
polygonOffsetUnits: gameLibMaterial.polygonOffsetUnits,
alphaTest: gameLibMaterial.alphaTest,
clippingPlanes: gameLibMaterial.clippingPlanes,
clipShadows: gameLibMaterial.clipShadows,
overdraw: gameLibMaterial.overdraw,
visible: gameLibMaterial.visible,
side: gameLibMaterial.side,
color: new graphics.instance.Color(
gameLibMaterial.color.r,
gameLibMaterial.color.g,
gameLibMaterial.color.b
),
specular: new graphics.instance.Color(
gameLibMaterial.specular.r,
gameLibMaterial.specular.g,
gameLibMaterial.specular.b
),
shininess: gameLibMaterial.shininess,
lightMapIntensity: gameLibMaterial.lightMapIntensity,
aoMapIntensity: gameLibMaterial.aoMapIntensity,
emissive: new graphics.instance.Color(
gameLibMaterial.emissive.r,
gameLibMaterial.emissive.g,
gameLibMaterial.emissive.b
),
emissiveIntensity: gameLibMaterial.emissiveIntensity,
bumpScale: gameLibMaterial.bumpScale,
normalScale: gameLibMaterial.normalScale,
displacementScale: gameLibMaterial.displacementScale,
combine: gameLibMaterial.combine,
refractionRatio: gameLibMaterial.refractionRatio,
fog: gameLibMaterial.fog,
shading: gameLibMaterial.shading,
wireframe: gameLibMaterial.wireframe,
wireframeLinewidth: gameLibMaterial.wireframeLineWidth,
wireframeLinecap: gameLibMaterial.wireframeLineCap,
wireframeLinejoin: gameLibMaterial.wireframeLineJoin,
vertexColors: gameLibMaterial.vertexColors,
skinning: gameLibMaterial.skinning,
morphTargets: gameLibMaterial.morphTargets,
morphNormals: gameLibMaterial.morphNormals
});
blenderMaps.push(
'diffuse',
'light',
'ao',
'emissive',
'bump',
'normal',
'displacement',
'specular',
'alpha',
'environment'
);
} else {
console.log("material type is not implemented yet: " + gameLibMaterial.materialType + " - material indexes could be screwed up");
}
if (blenderMaps.length > 0) {
var textureMaps = GameLib.D3.Texture.loadMaps(
gameLibMaterial,
blenderMaps,
instanceMaterial,
graphics,
uploadUrl,
progressCallback
);
Q.all(textureMaps).then(
function(){
defer.resolve(instanceMaterial);
}
).catch(
function(error){
console.log(error);
defer.reject(error);
}
)
} else {
defer.resolve(instanceMaterial);
}
return defer.promise;
};

37
src/game-lib-matrix-3.js Normal file
View File

@ -0,0 +1,37 @@
/**
* Matrix 3 Maths
* @param row0 GameLib.D3.Vector3
* @param row1 GameLib.D3.Vector3
* @param row2 GameLib.D3.Vector3
* @constructor
*/
GameLib.D3.Matrix3 = function(
row0,
row1,
row2
) {
this.identity();
if (row0) {
this.rows[0] = row0;
}
if (row1) {
this.rows[1] = row1;
}
if (row2) {
this.rows[2] = row2;
}
};
/**
* Set matrix to identity
*/
GameLib.D3.Matrix3.prototype.identity = function () {
this.rows = [
new GameLib.D3.Vector4(1, 0, 0),
new GameLib.D3.Vector4(0, 1, 0),
new GameLib.D3.Vector4(0, 0, 1)
];
};

173
src/game-lib-matrix-4.js Normal file
View File

@ -0,0 +1,173 @@
GameLib.D3.Matrix4 = function(
row0,
row1,
row2,
row3
) {
this.identity();
if (row0) {
this.rows[0] = row0;
}
if (row1) {
this.rows[1] = row1;
}
if (row2) {
this.rows[2] = row2;
}
if (row3) {
this.rows[3] = row3;
}
};
GameLib.D3.Matrix4.prototype.rotationMatrixX = function (radians) {
this.identity();
this.rows[1] = new GameLib.D3.Vector4(0, Math.cos(radians), -1 * Math.sin(radians), 0);
this.rows[2] = new GameLib.D3.Vector4(0, Math.sin(radians), Math.cos(radians), 0);
return this;
};
GameLib.D3.Matrix4.prototype.rotationMatrixY = function (radians) {
this.identity();
this.rows[0] = new GameLib.D3.Vector4(
Math.cos(radians),
0,
Math.sin(radians),
0
);
this.rows[2] = new GameLib.D3.Vector4(
-1 * Math.sin(radians),
0,
Math.cos(radians),
0
);
return this;
};
GameLib.D3.Matrix4.prototype.rotationMatrixZ = function (radians) {
this.identity();
this.rows[0] = new GameLib.D3.Vector4(Math.cos(radians), -1 * Math.sin(radians), 0, 0);
this.rows[1] = new GameLib.D3.Vector4(Math.sin(radians), Math.cos(radians), 0, 0);
return this;
};
GameLib.D3.Matrix4.prototype.rotateX = function (radians, point) {
this.identity();
this.rotationMatrixX(radians);
return this.multiply(point);
};
GameLib.D3.Matrix4.prototype.rotateY = function (radians, point) {
this.identity();
this.rotationMatrixY(radians);
return this.multiply(point);
};
GameLib.D3.Matrix4.prototype.rotateZ = function (radians, point) {
this.identity();
this.rotationMatrixZ(radians);
return this.multiply(point);
};
GameLib.D3.Matrix4.prototype.multiply = function (mvp) {
if (mvp instanceof GameLib.D3.Vector4) {
return new GameLib.D3.Vector4(
this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z + this.rows[0].w * mvp.w,
this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z + this.rows[1].w * mvp.w,
this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z + this.rows[2].w * mvp.w,
this.rows[3].x * mvp.x + this.rows[3].y * mvp.y + this.rows[3].z * mvp.z + this.rows[3].w * mvp.w
);
} else if (mvp instanceof GameLib.D3.Vector3) {
return new GameLib.D3.Vector3(
this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z,
this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z,
this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z
);
}
};
GameLib.D3.Matrix4.prototype.identity = function () {
this.rows = [
new GameLib.D3.Vector4(1, 0, 0, 0),
new GameLib.D3.Vector4(0, 1, 0, 0),
new GameLib.D3.Vector4(0, 0, 1, 0),
new GameLib.D3.Vector4(0, 0, 0, 1)
];
};
GameLib.D3.Matrix4.prototype.lookAt = function (position, target, up) {
var pv = new GameLib.D3.Vector3(position.x, position.y, position.z);
var z = pv.subtract(target).normalize();
if (z.squared() === 0) {
z.z = 1;
}
var x = up.cross(z).normalize();
if (x.squared() === 0) {
z.x += 0.0001;
x = up.cross(z).normalize();
}
var y = z.cross(x);
this.rows[0].x = x.x;
this.rows[0].y = x.y;
this.rows[0].z = x.z;
this.rows[1].x = y.x;
this.rows[1].y = y.y;
this.rows[1].z = y.z;
this.rows[2].x = z.x;
this.rows[2].y = z.y;
this.rows[2].z = z.z;
return this;
// te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
// te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
// te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
// var matrix4 = new Matrix4();
//
// matrix4.rows[0] = side.negative();
// matrix4.rows[1] = _up;
// matrix4.rows[2] = forward;
//
// matrix4.setColumn(0, side.negative());
// matrix4.setColumn(1, _up);
// matrix4.setColumn(2, forward);
//return matrix4;
// return new Matrix4(
// new Vector4(
// side.x,
// side.y,
// side.z,
// side.negative().dot(position)
// ),
// new Vector4(
// _up.x,
// _up.y,
// _up.z,
// _up.negative().dot(position)
// ),
// new Vector4(
// forward.negative().x,
// forward.negative().y,
// forward.negative().z,
// forward.dot(position)
// )
// )
};

540
src/game-lib-mesh.js Normal file
View File

@ -0,0 +1,540 @@
/**
* Mesh Superset
* @param id
* @param path
* @param name
* @param meshType
* @param vertices
* @param faces
* @param skeleton
* @param faceVertexUvs
* @param skinIndices
* @param skinWeights
* @param materials
* @param position
* @param quaternion
* @param rotation
* @param scale
* @param up
* @param physics
* @param parentMeshId
* @param parentSceneId
* @param rawData
* @constructor
*/
GameLib.D3.Mesh = function(
id,
path,
name,
meshType,
vertices,
faces,
skeleton,
faceVertexUvs,
skinIndices,
skinWeights,
materials,
position,
quaternion,
rotation,
scale,
up,
physics,
parentMeshId,
parentSceneId,
rawData
) {
this.id = id;
this.path = path;
this.name = name;
this.meshType = meshType;
this.vertices = vertices;
this.faces = faces;
if (typeof skeleton == 'undefined') {
skeleton = null;
}
this.skeleton = skeleton;
if (typeof faceVertexUvs == 'undefined') {
faceVertexUvs = [];
}
this.faceVertexUvs = faceVertexUvs;
if (typeof skinIndices == 'undefined') {
skinIndices = [];
}
this.skinIndices = skinIndices;
if (typeof skinWeights == 'undefined') {
skinWeights = [];
}
this.skinWeights = skinWeights;
if (typeof materials == 'undefined') {
materials = [];
}
this.materials = materials;
if (typeof position == 'undefined') {
position = new GameLib.D3.Vector3(0,0,0);
}
this.position = position;
if (typeof quaternion == 'undefined') {
new GameLib.D3.Vector4();
}
this.quaternion = quaternion;
if (typeof rotation == 'undefined') {
rotation = new GameLib.D3.Vector3(0,0,0);
}
this.rotation = rotation;
if (typeof scale == 'undefined') {
scale = new GameLib.D3.Vector3(1,1,1);
}
this.scale = scale;
if (typeof up == 'undefined') {
up = new GameLib.D3.Vector3(0,1,0);
}
this.up = up;
this.physics = physics;
this.parentMeshId = parentMeshId;
this.parentSceneId = parentSceneId;
this.rawData = null;// rawData;
};
/**
* Mesh Type
* @type {number}
*/
GameLib.D3.Mesh.TYPE_NORMAL = 0;
GameLib.D3.Mesh.TYPE_SKINNED = 1;
/**
* Creates a THREE Mesh from GameLib.D3.Mesh
* @param gameLibMesh GameLib.D3.Mesh
* @param instanceGeometry
* @param instanceMaterial
* @param graphics
* @returns {*}
*/
GameLib.D3.Mesh.createInstanceMesh = function(gameLibMesh, instanceGeometry, instanceMaterial, graphics) {
var threeMesh = null;
if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_NORMAL) {
threeMesh = new graphics.instance.Mesh(instanceGeometry, instanceMaterial);
}
if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_SKINNED) {
var bones = gameLibMesh.skeleton.bones;
var skinIndices = gameLibMesh.skinIndices;
var skinWeights = gameLibMesh.skinWeights;
var threeBones = [];
for (var bi = 0; bi < bones.length; bi++) {
var bone = new graphics.instance.Bone();
bone.name = bones[bi].name;
bone.position.x = bones[bi].position.x;
bone.position.y = bones[bi].position.y;
bone.position.z = bones[bi].position.z;
bone.rotation.x = bones[bi].rotation.x;
bone.rotation.y = bones[bi].rotation.y;
bone.rotation.z = bones[bi].rotation.z;
bone.quaternion.x = bones[bi].quaternion.x;
bone.quaternion.y = bones[bi].quaternion.y;
bone.quaternion.z = bones[bi].quaternion.z;
bone.quaternion.w = bones[bi].quaternion.w;
bone.scale.x = bones[bi].scale.x;
bone.scale.y = bones[bi].scale.y;
bone.scale.z = bones[bi].scale.z;
bone.up.x = bones[bi].up.x;
bone.up.y = bones[bi].up.y;
bone.up.z = bones[bi].up.z;
threeBones.push(bone);
}
/**
* Setup the bone relationships
*/
for (var br = 0; br < bones.length; br++) {
for (var cbi = 0; cbi < bones[br].childBoneIds.length; cbi++) {
threeBones[br].add(threeBones[bones[br].childBoneIds[cbi]]);
}
}
/**
* Setup bones (indexes)
*/
for (var si = 0; si < skinIndices.length; si++) {
instanceGeometry.skinIndices.push(
new graphics.instance.Vector4(
skinIndices[si].x,
skinIndices[si].y,
skinIndices[si].z,
skinIndices[si].w
)
);
}
/**
* Setup bones (weights)
*/
for (var sw = 0; sw < skinWeights.length; sw++) {
instanceGeometry.skinWeights.push(
new graphics.instance.Vector4(
skinWeights[sw].x,
skinWeights[sw].y,
skinWeights[sw].z,
skinWeights[sw].w
)
);
}
threeMesh = new graphics.instance.SkinnedMesh(instanceGeometry, instanceMaterial);
var skeleton = new graphics.instance.Skeleton(threeBones);
skeleton.useVertexTexture = gameLibMesh.skeleton.useVertexTexture;
for (var i = 0; i < bones.length; i++) {
if (bones[i].parentBoneId === null) {
threeMesh.add(threeBones[i]);
break;
}
}
threeMesh.bind(skeleton);
threeMesh.pose();
threeMesh.skeleton.skeletonHelper = new graphics.instance.SkeletonHelper(threeMesh);
threeMesh.skeleton.skeletonHelper.material.linewidth = 5;
}
if (threeMesh == null) {
console.log('cannot handle meshes of type ' + gameLibMesh.meshType + ' yet.');
}
gameLibMesh.threeMeshId = threeMesh.id;
return threeMesh;
};
GameLib.D3.prototype.invertWindingOrder = function(triangles) {
for (var i = 0; i < triangles.length; i++) {
var v1 = triangles[i].v1;
triangles[i].v1 = triangles[i].v2;
triangles[i].v2 = v1;
var backupUV = triangles[i].triangle.v1uv;
triangles[i].triangle.v1uv = triangles[i].triangle.v2uv;
triangles[i].triangle.v2uv = backupUV;
}
return triangles;
};
/**
* This function resets a the winding order of a mesh from a reference point V (the average center of the mesh)
*/
GameLib.D3.prototype.resetWindingOrder = function(faces, vertices) {
var vertexList = new GameLib.D3.Vector3.Points();
for (var v = 0; v < vertices.length; v++) {
vertexList.add(new GameLib.D3.Vector3(
vertices[v].position.x,
vertices[v].position.y,
vertices[v].position.z
));
}
var V = vertexList.average();
var triangles = [];
for (var s = 0; s < faces.length; s += 3) {
var v0 = faces[s];
var v1 = faces[s+1];
var v2 = faces[s+2];
triangles.push(
{
v0 : v0,
v1 : v1,
v2 : v2,
edges : [
{v0: v0, v1: v1},
{v0: v1, v1: v2},
{v0: v2, v1: v0}
],
winding : 0,
edgeIndex : -1,
processed : false
}
);
}
for (var i = 0; i < triangles.length; i++) {
if (
GameLib.D3.Vector3.clockwise(
vertices[triangles[i].v0].position,
vertices[triangles[i].v1].position,
vertices[triangles[i].v2].position,
V
)
) {
console.log('clockwise');
var bv1 = triangles[i].v1;
triangles[i].v1 = triangles[i].v2;
triangles[i].v2 = bv1;
} else {
console.log('not clockwise');
}
}
return triangles;
};
/**
* This function resets the winding order for triangles in faces, given an initial triangle and orientation edge
* used pseudocode from
* http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh
* We need to use a graph traversal algorithm,
* lets assume we have method that returns neighbor of triangle on given edge
*
* neighbor_on_egde( next_tria, edge )
*
* to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it
* processed = set of processed triangles; initial empty
*
* while to_process is not empty:
* next_tria, orientation_edge = to_process.pop()
* add next_tria in processed
* if next_tria is not opposite oriented than orientation_edge:
* change next_tria (ABC) orientation (B<->C)
* for each edge (AB) in next_tria:
* neighbor_tria = neighbor_on_egde( next_tria, edge )
* if neighbor_tria exists and neighbor_tria not in processed:
* to_process add (neighbor_tria, edge opposite oriented (BA))
* @param faces GameLib.D3.TriangleFace[]
* @param orientationEdge GameLib.D3.Vector2
* @returns {Array}
*/
GameLib.D3.fixWindingOrder = function(faces, orientationEdge) {
/**
* Checks if a TriangleFace belonging to a TriangleEdge has already been processed
* @param processed TriangleEdge[]
* @param triangle TriangleFace
* @returns {boolean}
*/
function inProcessed(processed, triangle) {
for (var i = 0; i < processed.length; i++) {
if (processed[i].triangle.equals(triangle)) {
return true;
}
}
return false;
}
/**
* Returns a neighbouring triangle on a specific edge - preserving the edge orientation
* @param edge GameLib.D3.Vector2
* @param faces GameLib.D3.TriangleFace[]
* @param currentTriangle
* @returns {*}
*/
function neighbourOnEdge(edge, faces, currentTriangle) {
for (var i = 0; i < faces.length; i++) {
if (
(faces[i].v0 == edge.x && faces[i].v1 == edge.y) ||
(faces[i].v1 == edge.x && faces[i].v2 == edge.y) ||
(faces[i].v2 == edge.x && faces[i].v0 == edge.y) ||
(faces[i].v0 == edge.y && faces[i].v1 == edge.x) ||
(faces[i].v1 == edge.y && faces[i].v2 == edge.x) ||
(faces[i].v2 == edge.y && faces[i].v0 == edge.x)
) {
var triangle = new GameLib.D3.TriangleFace(
faces[i].v0,
faces[i].v1,
faces[i].v2,
faces[i].materialIndex,
faces[i].v0uv,
faces[i].v1uv,
faces[i].v2uv
);
if (triangle.equals(currentTriangle)) {
continue;
}
return new GameLib.D3.TriangleEdge(
triangle,
edge
);
}
}
return null;
}
var toProcess = [
new GameLib.D3.TriangleEdge(
new GameLib.D3.TriangleFace(
faces[0].v0,
faces[0].v1,
faces[0].v2,
faces[0].materialIndex,
faces[0].v0uv,
faces[0].v1uv,
faces[0].v2uv
),
orientationEdge
)
];
var processed = [];
while (toProcess.length > 0) {
var triangleEdge = toProcess.pop();
/**
* If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed
* to have the same winding order)
*/
if (
(triangleEdge.triangle.v0 == triangleEdge.edge.x &&
triangleEdge.triangle.v1 == triangleEdge.edge.y) ||
(triangleEdge.triangle.v1 == triangleEdge.edge.x &&
triangleEdge.triangle.v2 == triangleEdge.edge.y) ||
(triangleEdge.triangle.v2 == triangleEdge.edge.x &&
triangleEdge.triangle.v0 == triangleEdge.edge.y)
) {
var backupV = triangleEdge.triangle.v1;
triangleEdge.triangle.v1 = triangleEdge.triangle.v2;
triangleEdge.triangle.v2 = backupV;
var backupUV = triangleEdge.triangle.v1uv;
triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv;
triangleEdge.triangle.v2uv = backupUV;
}
processed.push(triangleEdge);
var edges = [
new GameLib.D3.Vector2(
triangleEdge.triangle.v0,
triangleEdge.triangle.v1
),
new GameLib.D3.Vector2(
triangleEdge.triangle.v1,
triangleEdge.triangle.v2
),
new GameLib.D3.Vector2(
triangleEdge.triangle.v2,
triangleEdge.triangle.v0
)
];
for (var j = 0; j < edges.length; j++) {
var neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle);
if (neighbour && !inProcessed(processed, neighbour.triangle)) {
toProcess.push(neighbour);
}
}
}
/**
* In processed - we will have some duplicates - only add the unique ones
* @type {Array}
*/
var triangles = [];
for (var i = 0; i < processed.length; i++) {
var found = false;
for (var k = 0; k < triangles.length; k++) {
if (triangles[k].equals(processed[i].triangle)){
found = true;
break;
}
}
if (!found) {
triangles.push(processed[i].triangle);
}
}
return triangles;
};
/**
* This is a work-around function to fix polys which don't triangulate because
* they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around
* Z then Y axis
* @param verticesFlat []
* @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY
* @return []
*/
GameLib.D3.fixPolyZPlane = function(verticesFlat, grain) {
if ((verticesFlat.length % 3) != 0 && !(verticesFlat.length > 9)) {
console.log("The vertices are not in the right length : " + verticesFlat.length);
}
var vertices = [];
var points = new GameLib.D3.Vector4.Points();
for (var i = 0; i < verticesFlat.length; i += 3) {
points.add(new GameLib.D3.Vector3(
verticesFlat[i],
verticesFlat[i + 1],
verticesFlat[i + 2]
));
}
points.toOrigin();
points.maximizeXDistance(grain);
points.maximizeYDistance(grain);
for (i = 0; i < points.vectors.length; i++) {
vertices.push(
[
points.vectors[i].x,
points.vectors[i].y
]
);
}
return vertices;
};

32
src/game-lib-physics.js Normal file
View File

@ -0,0 +1,32 @@
/**
* Physics SuperSet Namespace Object
* @param id
* @param name
* @param engine GameLib.D3.Engine
* @param worlds
* @returns {{World: World}}
* @constructor
*/
GameLib.D3.Physics = function(
id,
name,
engine,
worlds
) {
this.id = id;
this.name = name;
this.engine = engine;
if (typeof worlds == 'undefined') {
worlds = [];
}
this.worlds = worlds;
};
/**
* Solver Types
* @type {number}
*/
GameLib.D3.Physics.SPLIT_SOLVER = 0x1;
GameLib.D3.Physics.GS_SOLVER = 0x2;

View File

@ -0,0 +1,36 @@
/**
* Contains a Poly vertex data structure
* @param localIndex
* @param mvertIndex
* @param uv GameLib.D3.Vector2
* @param materialIndex
* @param edgeIndex
* @constructor
*/
GameLib.D3.PolyVertex = function(
localIndex,
mvertIndex,
uv,
materialIndex,
edgeIndex
) {
this.localIndex = localIndex;
this.mvertIndex = mvertIndex;
this.uv = uv;
this.materialIndex = materialIndex;
this.edgeIndex = edgeIndex;
};
/**
* Clone a PolyVertex
* @returns {GameLib.D3.PolyVertex}
*/
GameLib.D3.PolyVertex.prototype.clone = function() {
return new GameLib.D3.PolyVertex(
this.localIndex,
this.mvertIndex,
this.uv.copy(),
this.materialIndex,
this.edgeIndex
)
};

View File

@ -0,0 +1,16 @@
/**
* Physics Raycast Vehicle Superset
* TODO: body + wheels[]
* @constructor
*/
GameLib.D3.RaycastVehicle = function(
) {
this.vehicleObject = null;
};
GameLib.D3.RaycastVehicle.prototype.GetWheelInfo = function(
) {
// note: need a way to determine which engine we are currently using
return this.vehicleObject.wheelInfos;
};

View File

@ -0,0 +1,16 @@
/**
* Physics Rigid Body Vehicle Superset
* TODO: body + wheels[]
* @constructor
*/
GameLib.D3.RigidVehicle = function(
) {
this.vehicleObject = null;
};
GameLib.D3.RigidVehicle.prototype.GetWheelInfo = function(
) {
// note: need a way to determine which engine we are currently using
return this.vehicleObject.wheelBodies;
};

View File

@ -0,0 +1,94 @@
/**
* RigidBody Superset
* @param mass
* @param friction
* @param position
* @param quaternion
* @param velocity
* @param angularVelocity
* @param linearDamping
* @param angularDamping
* @param allowSleep
* @param sleepSpeedLimit
* @param sleepTimeLimit
* @param collisionFilterGroup
* @param collisionFilterMask
* @param fixedRotation
* @param shape
* @returns {GameLib.D3.Physics.RigidBody}
* @constructor
*/
GameLib.D3.RigidBody = function(
mass,
friction,
position,
quaternion,
velocity,
angularVelocity,
linearDamping,
angularDamping,
allowSleep,
sleepSpeedLimit,
sleepTimeLimit,
collisionFilterGroup,
collisionFilterMask,
fixedRotation,
shape
) {
this.position = position || new GameLib.D3.Vector3();
this.velocity = velocity || new GameLib.D3.Vector3();
this.angularVelocity = angularVelocity || new GameLib.D3.Vector3();
this.quaternion = quaternion || new GameLib.D3.Vector4(0, 0, 0, 1);
this.mass = typeof mass == "undefined" ? 0 : mass;
this.friction = typeof friction == "undefined" ? 5 : friction;
this.linearDamping = typeof linearDamping == "undefined" ? 0.01 : linearDamping;
this.angularDamping = typeof angularDamping == "undefined" ? 0.01 : angularDamping;
this.allowSleep = typeof allowSleep == "undefined" ? true : allowSleep;
this.sleepSpeedLimit = typeof sleepSpeedLimit == "undefined" ? 0.1 : sleepSpeedLimit;
this.sleepTimeLimit = typeof sleepTimeLimit == "undefined" ? 1.0 : sleepTimeLimit;
this.collisionFilterGroup = typeof collisionFilterGroup == "undefined" ? 1 : collisionFilterGroup;
this.collisionFilterMask = typeof collisionFilterMask == "undefined" ? 1 : collisionFilterMask;
this.fixedRotation = typeof fixedRotation == "undefined" ? false : fixedRotation;
this.shape = typeof shape == "undefined" ? null : shape;
this.rigidBodyInstance = this.createRigidBodyInstance();
};
/**
*
* @returns {*}
*/
GameLib.D3.RigidBody.prototype.createRigidBodyInstance = function(
engine
) {
var rigidBody = null;
// Create the bodyObject
if(engine.engineType == GameLib.D3.Engine.ENGINE_TYPE_CANNON) {
rigidBody = new engine.instance.Body(
{
mass: mass,
friction: friction,
position: new engine.instance.Vec3(position.x, position.y, position.z),
velocity: new engine.instance.Vec3(velocity.x, velocity.y, velocity.z),
quaternion: new engine.instance.Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w),
angularVelocity: new engine.instance.Vec3(angularVelocity.x, angularVelocity.y, angularVelocity.z),
linearDamping: linearDamping,
angularDamping: angularDamping,
allowSleep: allowSleep,
sleepSpeedLimit: sleepSpeedLimit,
sleepTimeLimit: sleepTimeLimit,
collisionFilterGroup: collisionFilterGroup,
collisionFilterMask: collisionFilterMask,
fixedRotation: fixedRotation,
shape: shape
}
);
}
return rigidBody;
};

621
src/game-lib-scene.js Normal file
View File

@ -0,0 +1,621 @@
/**
* Scenes are objects putting meshes into 'world space'
* @param id
* @param path String
* @param name String
* @param meshes GameLib.D3.Mesh[]
* @param quaternion
* @param position
* @param rotation
* @param scale
* @param parentSceneId
* @param lights
* @param physics GameLib.D3.Physics
* @constructor
*/
GameLib.D3.Scene = function(
id,
path,
name,
meshes,
quaternion,
position,
rotation,
scale,
parentSceneId,
lights,
physics
) {
this.id = id;
this.path = path;
this.name = name;
if (this.name.trim() == "") {
this.name = 'unnamed';
}
if (typeof meshes == 'undefined') {
meshes = [];
}
this.meshes = meshes;
if (typeof quaternion == 'undefined') {
quaternion = new GameLib.D3.Vector4();
}
this.quaternion = quaternion;
if (typeof position == 'undefined') {
position = new GameLib.D3.Vector3(0,0,0);
}
this.position = position;
if (typeof rotation == 'undefined') {
rotation = new GameLib.D3.Vector3(0,0,0);
}
this.rotation = rotation;
if (typeof scale == 'undefined') {
scale = new GameLib.D3.Vector3(1,1,1);
}
this.scale = scale;
if (typeof parentSceneId == 'undefined') {
parentSceneId = null;
}
this.parentSceneId = parentSceneId;
if (typeof lights == 'undefined') {
lights = [];
}
this.lights = lights;
if (typeof physics == 'undefined') {
physics = [];
}
this.physics = physics;
};
/**
* Loads a scene directly from the API
* @param gameLibScene GameLib.D3.Scene
* @param onLoaded callback
* @param graphics GameLib.D3.Graphics
* @param uploadUrl String
* @param progressCallback callback
* @param apiUrl
*/
GameLib.D3.Scene.loadSceneFromApi = function(
gameLibScene,
onLoaded,
graphics,
uploadUrl,
progressCallback,
apiUrl
) {
/**
* First check if this is a client or server side request
*/
if (typeof XMLHttpRequest == 'undefined') {
console.warn('implement server side loading from API here');
return onLoaded(null, new Error('not implemented'));
}
var xhr = new XMLHttpRequest();
xhr.open(
'GET',
apiUrl + '/scene/load' + gameLibScene.path + '/' + gameLibScene.name
);
xhr.onreadystatechange = function(xhr) {
return function() {
if (xhr.readyState == 4) {
var response = JSON.parse(xhr.responseText);
if (!response.scene || response.scene.length == 0) {
return onLoaded(null, null, new Error('Could not load scene'));
}
var scene = response.scene[0];
var physics3ds = [];
if (scene.physics && scene.physics.length > 0) {
for (var p = 0; p < scene.physics.length; p++) {
var physics = scene.physics[p];
var engine = null;
if (physics.engine.engineType == GameLib.D3.Engine.ENGINE_TYPE_CANNON) {
engine = new GameLib.D3.Engine(
GameLib.D3.Engine.ENGINE_TYPE_CANNON,
CANNON
);
}
var physics3d = new GameLib.D3.Physics(
physics.id,
physics.name,
engine,
null
);
var worlds3d = [];
for (var w = 0; w < physics.worlds.length; w++) {
var world = physics.worlds[w];
var broadphase = world.broadphase;
var broadphase3d = new GameLib.D3.Physics.Broadphase(
broadphase.id,
broadphase.name,
broadphase.broadphaseType
);
var solver = world.solver;
var solver3d = new GameLib.D3.Physics.Solver(
solver.id,
solver.name,
solver.solverType,
solver.iterations,
solver.tolerance
);
var bodies = world.rigidBodies;
var bodies3d = [];
for (var b = 0; b < bodies.length; b++) {
var body = bodies[b];
//TODO: add all body properties here
var body3d = new GameLib.D3.Physics.RigidBody(
body.id,
body.name
);
bodies3d.push(body3d);
}
var world3d = new GameLib.D3.Physics.World(
null,
world.name,
physics3d,
new GameLib.D3.Vector3(
world.gravity.x,
world.gravity.y,
world.gravity.z
),
broadphase3d,
solver3d,
bodies3d
);
worlds3d.push(world3d);
}
physics3ds.push(physics3d);
}
}
var lights3d = [];
for (var l = 0; l < scene.lights.length; l++) {
var light = scene.lights[l];
var light3d = new GameLib.D3.Light(
light.id,
light.lightType,
light.name,
new GameLib.D3.Color(
light.color.r,
light.color.g,
light.color.b,
light.color.a
),
light.intensity,
new GameLib.D3.Vector3(
light.position.x,
light.position.y,
light.position.z
),
new GameLib.D3.Vector3(
light.targetPosition.x,
light.targetPosition.y,
light.targetPosition.z
),
new GameLib.D3.Vector4(
light.quaternion.x,
light.quaternion.y,
light.quaternion.z,
light.quaternion.w
),
new GameLib.D3.Vector3(
light.rotation.x,
light.rotation.y,
light.rotation.z
),
new GameLib.D3.Vector3(
light.scale.x,
light.scale.y,
light.scale.z
),
light.distance,
light.decay,
light.power,
light.angle,
light.penumbra
);
lights3d.push(light3d);
}
var scene3d = new GameLib.D3.Scene(
scene._id || scene.id,
scene.path,
scene.name,
scene.meshes,
new GameLib.D3.Vector4(
scene.quaternion.x,
scene.quaternion.y,
scene.quaternion.z,
scene.quaternion.w
),
new GameLib.D3.Vector3(
scene.position.x,
scene.position.y,
scene.position.z
),
new GameLib.D3.Vector3(
scene.rotation.x,
scene.rotation.y,
scene.rotation.z
),
new GameLib.D3.Vector3(
scene.scale.x,
scene.scale.y,
scene.scale.z
),
scene.parentSceneId,
lights3d,
physics3ds
);
GameLib.D3.Scene.loadScene(
scene3d,
onLoaded,
false,
graphics,
uploadUrl,
progressCallback
);
}
}
}(xhr);
xhr.send();
};
/**
* Loads a GameLib.D3.Scene object into a Graphics Instance Scene object
* @param gameLibScene GameLib.D3.Scene
* @param onLoaded callback when all meshes have loaded
* @param computeNormals set to true to compute new face and vertex normals during load
* @param graphics GameLib.D3.Graphics
* @param uploadUrl
* @param progressCallback
*/
GameLib.D3.Scene.loadScene = function(
gameLibScene,
onLoaded,
computeNormals,
graphics,
uploadUrl,
progressCallback
) {
console.log("loading scene " + gameLibScene.name);
graphics.isNotThreeThrow();
var meshQ = [];
for (var m = 0; m < gameLibScene.meshes.length; m++) {
var mesh = gameLibScene.meshes[m];
console.log("loading mesh " + mesh.name);
var geometry = new graphics.instance.Geometry();
var vertices = mesh.vertices;
var faces = mesh.faces;
var faceVertexUvs = mesh.faceVertexUvs;
var materials = mesh.materials;
/**
* Setup vertices
*/
for (var v = 0; v < vertices.length; v++) {
geometry.vertices.push(
new graphics.instance.Vector3(
vertices[v].position.x,
vertices[v].position.y,
vertices[v].position.z
)
)
}
/**
* Setup faces
*/
for (var f = 0; f < faces.length; f++) {
var face = new graphics.instance.Face3(
faces[f].v0,
faces[f].v1,
faces[f].v2,
new graphics.instance.Vector3(
faces[f].normal.x,
faces[f].normal.y,
faces[f].normal.z
),
new graphics.instance.Color(
faces[f].color.r,
faces[f].color.g,
faces[f].color.b
),
faces[f].materialIndex
);
face.vertexColors = [
new graphics.instance.Color(
faces[f].vertexColors[0].r,
faces[f].vertexColors[0].g,
faces[f].vertexColors[0].b
),
new graphics.instance.Color(
faces[f].vertexColors[1].r,
faces[f].vertexColors[1].g,
faces[f].vertexColors[1].b
),
new graphics.instance.Color(
faces[f].vertexColors[2].r,
faces[f].vertexColors[2].g,
faces[f].vertexColors[2].b
)
];
face.normal = new graphics.instance.Vector3(
faces[f].normal.x,
faces[f].normal.y,
faces[f].normal.z
);
face.vertexNormals = [
new graphics.instance.Vector3(
faces[f].vertexNormals[0].x,
faces[f].vertexNormals[0].y,
faces[f].vertexNormals[0].z
),
new graphics.instance.Vector3(
faces[f].vertexNormals[1].x,
faces[f].vertexNormals[1].y,
faces[f].vertexNormals[1].z
),
new graphics.instance.Vector3(
faces[f].vertexNormals[2].x,
faces[f].vertexNormals[2].y,
faces[f].vertexNormals[2].z
)
];
geometry.faces.push(face);
}
geometry.faceVertexUvs = [];
/**
* Setup face UVs
*/
for (var fm = 0; fm < faceVertexUvs.length; fm++) {
var faceMaterialVertexUvs = faceVertexUvs[fm];
geometry.faceVertexUvs[fm] = [];
for (var fuv = 0; fuv < faceMaterialVertexUvs.length; fuv++) {
geometry.faceVertexUvs[fm][fuv] = [];
geometry.faceVertexUvs[fm][fuv].push(
new graphics.instance.Vector2(
faceMaterialVertexUvs[fuv][0].x,
faceMaterialVertexUvs[fuv][0].y
),
new graphics.instance.Vector2(
faceMaterialVertexUvs[fuv][1].x,
faceMaterialVertexUvs[fuv][1].y
),
new graphics.instance.Vector2(
faceMaterialVertexUvs[fuv][2].x,
faceMaterialVertexUvs[fuv][2].y
)
);
}
}
/**
* Re-calculate normals (if we have to)
* @type {Array}
*/
if (computeNormals) {
geometry.computeFaceNormals();
geometry.computeVertexNormals();
}
var instanceMaterialLoaders = [];
/**
* Setup materials
*/
for (var mi = 0; mi < materials.length; mi++) {
instanceMaterialLoaders.push(
GameLib.D3.Material.createInstanceMaterial(
materials[mi],
graphics,
uploadUrl,
progressCallback
)
);
}
var result = Q.all(instanceMaterialLoaders).then(
function(mesh, geometry) {
return function(materials) {
console.log("loaded material : " + materials[0].name);
/**
* We don't support MultiMaterial atm - it doesn't work with raycasting
*/
var material = materials[0];
var threeMesh = GameLib.D3.Mesh.createInstanceMesh(
mesh,
geometry,
material,
graphics
);
threeMesh.name = mesh.name;
threeMesh.position.x = mesh.position.x;
threeMesh.position.y = mesh.position.y;
threeMesh.position.z = mesh.position.z;
threeMesh.rotation.x = mesh.rotation.x;
threeMesh.rotation.y = mesh.rotation.y;
threeMesh.rotation.z = mesh.rotation.z;
threeMesh.scale.x = mesh.scale.x;
threeMesh.scale.y = mesh.scale.y;
threeMesh.scale.z = mesh.scale.z;
threeMesh.quaternion.x = mesh.quaternion.x;
threeMesh.quaternion.y = mesh.quaternion.y;
threeMesh.quaternion.z = mesh.quaternion.z;
threeMesh.quaternion.w = mesh.quaternion.w;
return threeMesh;
};
}(mesh, geometry)
).catch(function(error){
console.log(error);
});
meshQ.push(result);
}
Q.all(meshQ).then(
function(instanceMeshes){
console.log("all meshes have loaded");
if (typeof onLoaded != 'undefined') {
var instanceLights = [];
for (var sli = 0; sli < gameLibScene.lights.length; sli++) {
var gameLibLight = gameLibScene.lights[sli];
var light = null;
if (gameLibLight.lightType == 'AmbientLight') {
light = new graphics.instance.AmbientLight(gameLibLight.color, gameLibLight.intensity);
}
if (gameLibLight.lightType == 'DirectionalLight') {
light = new graphics.instance.DirectionalLight(gameLibLight.color, gameLibLight.intensity);
}
if (gameLibLight.lightType == 'PointLight') {
light = new graphics.instance.PointLight(gameLibLight.color, gameLibLight.intensity);
light.distance = gameLibLight.distance;
light.decay = gameLibLight.decay;
}
if (gameLibLight.lightType == 'SpotLight') {
light = new graphics.instance.SpotLight(gameLibLight.color, gameLibLight.intensity);
light.distance = gameLibLight.distance;
light.angle = gameLibLight.angle;
light.penumbra = gameLibLight.penumbra;
light.decay = gameLibLight.decay;
}
light.position.x = gameLibLight.position.x;
light.position.y = gameLibLight.position.y;
light.position.z = gameLibLight.position.z;
light.rotation.x = gameLibLight.rotation.x;
light.rotation.y = gameLibLight.rotation.y;
light.rotation.z = gameLibLight.rotation.z;
if (light == null) {
console.warn('Does not support lights of type :' + gameLibLight.lightType + ', not imported');
} else {
light.name = gameLibLight.name;
instanceLights.push(light);
}
}
var instanceScene = new graphics.instance.Scene();
instanceScene.name = gameLibScene.name;
instanceScene.position.x = gameLibScene.position.x;
instanceScene.position.y = gameLibScene.position.y;
instanceScene.position.z = gameLibScene.position.z;
instanceScene.rotation.x = gameLibScene.rotation.x;
instanceScene.rotation.y = gameLibScene.rotation.y;
instanceScene.rotation.z = gameLibScene.rotation.z;
instanceScene.scale.x = gameLibScene.scale.x;
instanceScene.scale.y = gameLibScene.scale.y;
instanceScene.scale.z = gameLibScene.scale.z;
instanceScene.quaternion.x = gameLibScene.quaternion.x;
instanceScene.quaternion.y = gameLibScene.quaternion.y;
instanceScene.quaternion.z = gameLibScene.quaternion.z;
instanceScene.quaternion.w = gameLibScene.quaternion.w;
for (var m = 0; m < instanceMeshes.length; m++) {
instanceScene.add(instanceMeshes[m]);
}
for (var l = 0; l < instanceLights.length; l++) {
instanceScene.add(instanceLights[l]);
}
onLoaded(
gameLibScene,
{
scene: instanceScene,
lights: instanceLights,
meshes: instanceMeshes
}
);
}
}).catch(
function(error){
console.log(error);
}
);
};

37
src/game-lib-shape.js Normal file
View File

@ -0,0 +1,37 @@
/**
* Physics Shape Superset
* @constructor
*/
GameLib.D3.Physics.Shape = function(
shapeObject, // Physics engine specific
shapeType
) {
this.shapeObject = shapeObject;
this.shapeType = shapeType;
this.scale = new GameLib.D3.Vector3(1, 1, 1);
};
GameLib.D3.Physics.SHAPE_TYPE_SPHERE = 1;
GameLib.D3.Physics.SHAPE_TYPE_BOX = 2;
GameLib.D3.Physics.SHAPE_TYPE_TRIMESH = 3;
GameLib.D3.Physics.SHAPE_TYPE_CYLINDER = 4;
GameLib.D3.Physics.Shape.prototype.Update = function() {
if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
if(this.shapeType === GameLib.D3.Physics.SHAPE_TYPE_TRIMESH) {
this.shapeObject.setScale(
new this.physics.CANNON.Vec3(
this.scale.x,
this.scale.y,
this.scale.z
)
);
this.shapeObject.updateAABB();
this.shapeObject.updateNormals();
this.shapeObject.updateEdges();
this.shapeObject.updateBoundingSphereRadius();
this.shapeObject.updateTree();
}
}
};

69
src/game-lib-skeleton.js Normal file
View File

@ -0,0 +1,69 @@
/**
* Skeleton Superset
* @param id
* @param bones GameLib.D3.Bone
* @param boneInverses
* @param useVertexTexture
* @param boneTextureWidth
* @param boneTextureHeight
* @param boneMatrices
* @param boneTexture
* @constructor
*/
GameLib.D3.Skeleton = function(
id,
bones,
boneInverses,
useVertexTexture,
boneTextureWidth,
boneTextureHeight,
boneMatrices,
boneTexture
) {
this.id = id;
this.bones = bones;
/**
* An array of Matrix4s that represent the inverse of the matrixWorld of the individual bones.
* @type GameLib.D3.Matrix4[]
*/
if (typeof boneInverses == 'undefined') {
boneInverses = [];
}
this.boneInverses = boneInverses;
/**
* Use a vertex texture in the shader - allows for more than 4 bones per vertex, not supported by all devices
* @type {boolean}
*/
if (typeof useVertexTexture == 'undefined') {
useVertexTexture = false;
}
this.useVertexTexture = useVertexTexture;
if (this.useVertexTexture == true) {
console.warn('support for vertex texture bones is not supported yet - something could break somewhere');
}
if (typeof boneTextureWidth == 'undefined') {
boneTextureWidth = 0;
}
this.boneTextureWidth = boneTextureWidth;
if (typeof boneTextureHeight == 'undefined') {
boneTextureHeight = 0;
}
this.boneTextureHeight = boneTextureHeight;
if (typeof boneMatrices == 'undefined') {
boneMatrices = [];
}
this.boneMatrices = boneMatrices;
if (typeof boneTexture == 'undefined') {
boneTexture = [];
}
this.boneTexture = boneTexture;
};

65
src/game-lib-sky-box.js Normal file
View File

@ -0,0 +1,65 @@
GameLib.D3.SkyBox = function (
) {
this.id = null;
this.texturesFolder = null;
};
GameLib.D3.SkyBox.prototype.Load = function (
texturesFolder
) {
this.texturesFolder = texturesFolder;
this.textures = [];
this.materials = [];
this.mesh = {};
this.scene = new THREE.Scene();
this.textureCube = null;
var textureLoader = new THREE.TextureLoader();
// this textures are used to display the skybox
this.textures.push(textureLoader.load(this.texturesFolder + "px.png"));
this.textures.push(textureLoader.load(this.texturesFolder + "nx.png"));
this.textures.push(textureLoader.load(this.texturesFolder + "py.png"));
this.textures.push(textureLoader.load(this.texturesFolder + "ny.png"));
this.textures.push(textureLoader.load(this.texturesFolder + "pz.png"));
this.textures.push(textureLoader.load(this.texturesFolder + "nz.png"));
// assign textures to each cube face
for (var i = 0; i < 6; i ++) {
this.materials.push(new THREE.MeshBasicMaterial({ map: this.textures[i] }));
}
// create cube geometry
this.mesh = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE.MeshFaceMaterial(this.materials));
this.mesh.applyMatrix(new THREE.Matrix4().makeScale(1, 1, -1));
this.scene.add(this.mesh);
// Load env textureCube
// this is used for reflections on meshes
// mesh.material.envMap = this.textureCube;
this.textureCube = new THREE.CubeTextureLoader().load([
this.texturesFolder + "px.png", this.texturesFolder + "nx.png",
this.texturesFolder + "py.png", this.texturesFolder + "ny.png",
this.texturesFolder + "pz.png", this.texturesFolder + "nz.png"
]);
};
GameLib.D3.SkyBox.prototype.Render = function (
threeRenderer,
threeCamera
) {
var cameraPosition = new THREE.Vector3(threeCamera.position.x, threeCamera.position.y, threeCamera.position.z);
threeCamera.position.set(0, 0, 0);
var gl = threeRenderer.context;
gl.disable(gl.DEPTH_TEST);
threeRenderer.render(this.scene, threeCamera);
gl.enable(gl.DEPTH_TEST);
threeCamera.position.copy(cameraPosition);
};

38
src/game-lib-solver.js Normal file
View File

@ -0,0 +1,38 @@
/**
* Physics Solver Superset
* @param id
* @param name
* @param solverType
* @param iterations
* @param tolerance
* @constructor
*/
GameLib.D3.Physics.Solver = function(
id,
name,
solverType,
iterations,
tolerance
) {
this.id = id;
if (typeof name == 'undefined') {
if (solverType == GameLib.D3.Physics.SPLIT_SOLVER) {
name = 'split solver';
} else if (solverType == GameLib.D3.Physics.GS_SOLVER) {
name = 'gs solver';
} else {
name = 'unknown solver';
}
}
this.name = name;
this.solverType = solverType;
this.iterations = iterations;
this.tolerance = tolerance;
};
/**
* Solver Types
* @type {number}
*/
GameLib.D3.Physics.SPLIT_SOLVER = 0x1;
GameLib.D3.Physics.GS_SOLVER = 0x2;

398
src/game-lib-texture.js Normal file
View File

@ -0,0 +1,398 @@
/**
* Texture Superset
* @param id
* @param name
* @param image
* @param wrapS
* @param wrapT
* @param repeat
* @param data
* @param format
* @param mapping
* @param magFilter
* @param minFilter
* @param textureType
* @param anisotropy
* @param offset
* @param generateMipmaps
* @param flipY
* @param mipmaps
* @param unpackAlignment
* @param premultiplyAlpha
* @param encoding
* @constructor
*/
GameLib.D3.Texture = function(
id,
name,
image,
wrapS,
wrapT,
repeat,
data,
format,
mapping,
magFilter,
minFilter,
textureType,
anisotropy,
offset,
generateMipmaps,
flipY,
mipmaps,
unpackAlignment,
premultiplyAlpha,
encoding
) {
this.id = id;
this.name = name;
this.image = image;
if (typeof wrapS == 'undefined') {
wrapS = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING;
}
this.wrapS = wrapS;
if (typeof wrapT == 'undefined') {
wrapT = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING;
}
this.wrapT = wrapT;
if (typeof repeat == 'undefined') {
repeat = new GameLib.D3.Vector2(1, 1);
}
this.repeat = repeat;
if (typeof data == 'undefined') {
data = null;
}
this.data = data;
if (typeof format == 'undefined') {
format = GameLib.D3.Texture.TYPE_RGBA_FORMAT;
}
this.format = format;
if (typeof mapping == 'undefined') {
mapping = GameLib.D3.Texture.TYPE_UV_MAPPING;
}
this.mapping = mapping;
if (typeof magFilter == 'undefined') {
magFilter = GameLib.D3.Texture.TYPE_LINEAR_FILTER;
}
this.magFilter = magFilter;
if (typeof minFilter == 'undefined') {
minFilter = GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER;
}
this.minFilter = minFilter;
if (typeof textureType == 'undefined') {
textureType = GameLib.D3.Texture.TYPE_UNSIGNED_BYTE;
}
this.textureType = textureType;
if (typeof anisotropy == 'undefined') {
anisotropy = 1;
}
this.anisotropy = anisotropy;
if (typeof offset == 'undefined') {
offset = new GameLib.D3.Vector2(0, 0);
}
this.offset = offset;
if (typeof generateMipmaps == 'undefined') {
generateMipmaps = true;
}
this.generateMipmaps = generateMipmaps;
if (typeof flipY == 'undefined') {
flipY = true;
}
this.flipY = flipY;
if (typeof mipmaps == 'undefined') {
mipmaps = [];
}
this.mipmaps = mipmaps;
if (typeof unpackAlignment == 'undefined') {
unpackAlignment = 4;
}
this.unpackAlignment = unpackAlignment;
if (typeof premultiplyAlpha == 'undefined') {
premultiplyAlpha = false;
}
this.premultiplyAlpha = premultiplyAlpha;
if (typeof encoding == 'undefined') {
encoding = GameLib.D3.Texture.TYPE_LINEAR_ENCODING;
}
this.encoding = encoding;
};
/**
* Texture Formats
* @type {number}
*/
GameLib.D3.Texture.TYPE_ALPHA_FORMAT = 1019;
GameLib.D3.Texture.TYPE_RGB_FORMAT = 1020;
GameLib.D3.Texture.TYPE_RGBA_FORMAT = 1021;
GameLib.D3.Texture.TYPE_LUMINANCE_FORMAT = 1022;
GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT = 1023;
GameLib.D3.Texture.TYPE_DEPTH_FORMAT = 1026;
/**
* Mapping modes
* @type {number}
*/
GameLib.D3.Texture.TYPE_UV_MAPPING = 300;
GameLib.D3.Texture.TYPE_CUBE_REFLECTION_MAPPING = 301;
GameLib.D3.Texture.TYPE_CUBE_REFRACTION_MAPPING = 302;
GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING = 303;
GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING = 304;
GameLib.D3.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING = 305;
GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING = 306;
GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING = 307;
/**
* Wrapping Modes
* @type {number}
*/
GameLib.D3.Texture.TYPE_REPEAT_WRAPPING = 1000;
GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING = 1001;
GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING = 1002;
/**
* Mipmap Filters
* @type {number}
*/
GameLib.D3.Texture.TYPE_NEAREST_FILTER = 1003;
GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER = 1004;
GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER = 1005;
GameLib.D3.Texture.TYPE_LINEAR_FILTER = 1006;
GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER = 1007;
GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER = 1008;
/**
* Texture Data Types
* @type {number}
*/
GameLib.D3.Texture.TYPE_UNSIGNED_BYTE = 1009;
GameLib.D3.Texture.TYPE_BYTE = 1010;
GameLib.D3.Texture.TYPE_SHORT = 1011;
GameLib.D3.Texture.TYPE_UNSIGNED_SHORT = 1012;
GameLib.D3.Texture.TYPE_INT = 1013;
GameLib.D3.Texture.TYPE_UNSIGNED_INT = 1014;
GameLib.D3.Texture.TYPE_FLOAT = 1015;
GameLib.D3.Texture.TYPE_HALF_FLOAT = 1025;
/**
* Encoding Modes
* @type {number}
*/
GameLib.D3.Texture.TYPE_LINEAR_ENCODING = 3000; // NO ENCODING AT ALL.
GameLib.D3.Texture.TYPE_SRGB_ENCODING = 3001;
GameLib.D3.Texture.TYPE_GAMMA_ENCODING = 3007; // USES GAMMA_FACTOR, FOR BACKWARDS COMPATIBILITY WITH WEBGLRENDERER.GAMMAINPUT/GAMMAOUTPUT
GameLib.D3.Texture.TYPE_RGBE_ENCODING = 3002; // AKA RADIANCE.
GameLib.D3.Texture.TYPE_LOG_LUV_ENCODING = 3003;
GameLib.D3.Texture.TYPE_RGBM7_ENCODING = 3004;
GameLib.D3.Texture.TYPE_RGBM16_ENCODING = 3005;
GameLib.D3.Texture.TYPE_RGBD_ENCODING = 3006; // MAXRANGE IS 256.
/**
* Defers loading of an image and resolves once image is loaded
* @param gameLibTexture GameLib.D3.Texture
* @param instanceMaterial
* @param instanceMaterialMapType
* @param graphics GameLib.D3.Graphics
* @param uploadUrl String
* @param progressCallback
* @returns {Promise}
*/
GameLib.D3.Texture.loadMap = function(
gameLibTexture,
instanceMaterial,
instanceMaterialMapType,
graphics,
uploadUrl,
progressCallback
) {
var defer = Q.defer();
var imagePath = null;
var textureLoader = new graphics.instance.TextureLoader();
if (gameLibTexture && gameLibTexture.image && gameLibTexture.image.filename) {
/**
* Else, load from upload source
*/
imagePath = uploadUrl + '/' + gameLibTexture.image.filename;
}
if (imagePath) {
textureLoader.crossOrigin = '';
textureLoader.load(
imagePath,
function(texture) {
/**
* onLoad
*/
instanceMaterial[instanceMaterialMapType] = texture;
instanceMaterial[instanceMaterialMapType].name = gameLibTexture.name;
instanceMaterial[instanceMaterialMapType].anisotropy = gameLibTexture.anisotropy;
instanceMaterial[instanceMaterialMapType].encoding = gameLibTexture.encoding;
instanceMaterial[instanceMaterialMapType].flipY = gameLibTexture.flipY;
/**
* We don't restore the format since this changing from OS to OS and breaks the implementation sometimes
*/
instanceMaterial[instanceMaterialMapType].generateMipmaps = gameLibTexture.generateMipmaps;
instanceMaterial[instanceMaterialMapType].magFilter = gameLibTexture.magFilter;
instanceMaterial[instanceMaterialMapType].minFilter = gameLibTexture.minFilter;
instanceMaterial[instanceMaterialMapType].mapping = gameLibTexture.mapping;
instanceMaterial[instanceMaterialMapType].mipmaps = gameLibTexture.mipmaps;
instanceMaterial[instanceMaterialMapType].offset = new graphics.instance.Vector2(
gameLibTexture.offset.x,
gameLibTexture.offset.y
);
instanceMaterial[instanceMaterialMapType].premultiplyAlpha = gameLibTexture.premultiplyAlpha;
instanceMaterial[instanceMaterialMapType].textureType = gameLibTexture.textureType;
instanceMaterial[instanceMaterialMapType].wrapS = gameLibTexture.wrapS;
instanceMaterial[instanceMaterialMapType].wrapT = gameLibTexture.wrapT;
instanceMaterial[instanceMaterialMapType].unpackAlignment = gameLibTexture.unpackAlignment;
instanceMaterial.needsUpdate = true;
defer.resolve(true);
},
function(xhr) {
/**
* onProgress
*/
if (progressCallback) {
progressCallback(Math.round(xhr.loaded / xhr.total * 100));
}
},
function(error) {
/**
* onError
*/
console.log("an error occurred while trying to load the image : " + imagePath);
defer.resolve(null);
}
);
} else {
defer.resolve(null);
}
return defer.promise;
};
/**
* Returns an array of image loading Promises
* @param gameLibMaterial
* @param blenderMaps
* @param instanceMaterial
* @param graphics GameLib.D3.Graphics
* @param uploadUrl String
* @param progressCallback
* @returns Q[]
*/
GameLib.D3.Texture.loadMaps = function(
gameLibMaterial,
blenderMaps,
instanceMaterial,
graphics,
uploadUrl,
progressCallback
) {
var textureMaps = [];
for (var ti = 0; ti < blenderMaps.length; ti++) {
var map = blenderMaps[ti];
if (gameLibMaterial.maps.hasOwnProperty(map)) {
var blenderTexture = gameLibMaterial.maps[map];
if (
blenderTexture &&
blenderTexture.image &&
blenderTexture.image.filename
) {
var instanceMap = null;
if (map == 'alpha') {
instanceMap = 'alhpaMap';
}
if (map == 'ao') {
instanceMap = 'aoMap';
}
if (map == 'bump') {
instanceMap = 'bumpMap';
}
if (map == 'displacement') {
instanceMap = 'displacementMap';
}
if (map == 'emissive') {
instanceMap = 'emissiveMap';
}
if (map == 'environment') {
instanceMap = 'envMap';
}
if (map == 'light') {
instanceMap = 'lightMap';
}
if (map == 'specular') {
instanceMap = 'specularMap';
}
if (map == 'diffuse') {
instanceMap = 'map';
}
if (map == 'roughness') {
instanceMap = 'roughnessMap';
}
if (map == 'metalness') {
instanceMap = 'metalnessMap';
}
if (instanceMap == null) {
console.warn("unsupported map type : " + map);
}
textureMaps.push(
GameLib.D3.Texture.loadMap(
gameLibMaterial.maps[map],
instanceMaterial,
instanceMap,
graphics,
uploadUrl,
progressCallback
)
);
}
}
}
return textureMaps;
};

View File

@ -0,0 +1,13 @@
/**
* TriangleEdge
* @param triangle
* @param edge
* @constructor
*/
GameLib.D3.TriangleEdge = function(
triangle,
edge
) {
this.triangle = triangle;
this.edge = edge;
};

View File

@ -0,0 +1,125 @@
/**
* TriangleFace
* @param v0
* @param v1
* @param v2
* @param materialIndex
* @param v0uv
* @param v1uv
* @param v2uv
* @param color
* @param vertexColors
* @param vertexNormals
* @param normal
* @constructor
*/
GameLib.D3.TriangleFace = function(
v0,
v1,
v2,
materialIndex,
v0uv,
v1uv,
v2uv,
color,
vertexColors,
vertexNormals,
normal
) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.materialIndex = materialIndex;
this.v0uv = v0uv;
this.v1uv = v1uv;
this.v2uv = v2uv;
if (!color) {
color = new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff);
}
this.color = color;
if (!vertexColors) {
vertexColors = [
new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff),
new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff),
new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff)
];
}
this.vertexColors = vertexColors;
if (!vertexNormals) {
vertexNormals = [
new GameLib.D3.Vector3(),
new GameLib.D3.Vector3(),
new GameLib.D3.Vector3()
]
}
this.vertexNormals = vertexNormals;
if (!normal) {
normal = new GameLib.D3.Vector3(0);
}
this.normal = normal;
};
/**
* Clone a TriangleFace
* @returns {GameLib.D3.TriangleFace}
*/
GameLib.D3.TriangleFace.prototype.clone = function(){
return new GameLib.D3.TriangleFace(
this.v0,
this.v1,
this.v2,
this.materialIndex,
this.v0uv.copy(),
this.v1uv.copy(),
this.v2uv.copy()
);
};
/**
* Returns true if two triangles are equal (their vertex indices match in some order)
* @param triangle
* @returns {boolean}
*/
GameLib.D3.TriangleFace.prototype.equals = function(triangle) {
return !!(
(
(this.v0 == triangle.v0) &&
(this.v1 == triangle.v1) &&
(this.v2 == triangle.v2)
)
||
(
(this.v0 == triangle.v0) &&
(this.v1 == triangle.v2) &&
(this.v2 == triangle.v1)
)
||
(
(this.v0 == triangle.v1) &&
(this.v1 == triangle.v0) &&
(this.v2 == triangle.v2)
)
||
(
(this.v0 == triangle.v1) &&
(this.v1 == triangle.v2) &&
(this.v2 == triangle.v0)
)
||
(
(this.v0 == triangle.v2) &&
(this.v1 == triangle.v0) &&
(this.v2 == triangle.v1)
)
||
(
(this.v0 == triangle.v2) &&
(this.v1 == triangle.v1) &&
(this.v2 == triangle.v0)
));
};

27
src/game-lib-vector-2.js Normal file
View File

@ -0,0 +1,27 @@
GameLib.D3.Vector2 = function(x, y) {
this.x = 0;
this.y = 0;
if (x) {
this.x = x;
}
if (y) {
this.y = y;
}
};
GameLib.D3.Vector2.prototype.copy = function() {
return new GameLib.D3.Vector2(
this.x,
this.y
);
};
GameLib.D3.Vector2.prototype.equals = function(v) {
return !!(((this.x == v.x) &&
(this.y == v.y)) ||
((this.y == v.x) &&
(this.x == v.y)));
};

134
src/game-lib-vector-3.js Normal file
View File

@ -0,0 +1,134 @@
GameLib.D3.Vector3 = function(x, y, z) {
this.x = 0;
this.y = 0;
this.z = 0;
if (x) {
this.x = x;
}
if (y) {
this.y = y;
}
if (z) {
this.z = z;
}
};
GameLib.D3.Vector3.prototype.subtract = function (v) {
if (v instanceof GameLib.D3.Vector3) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
}
if (v instanceof GameLib.D3.Vector4) {
console.warn("trying to subtract vector of bigger length (4 vs 3))");
}
return this;
};
GameLib.D3.Vector3.prototype.cross = function (v) {
return new GameLib.D3.Vector3(
this.y * v.z - this.z * v.y,
this.z * v.x - this.x * v.z,
this.x * v.y - this.y * v.x
);
};
GameLib.D3.Vector3.prototype.negative = function () {
this.x *= -1;
this.y *= -1;
this.z *= -1;
return this;
};
GameLib.D3.Vector3.clockwise = function (u, v, w, viewPoint) {
var normal = GameLib.D3.Vector3.normal(u, v, w);
var uv = u.copy();
var winding = normal.dot(uv.subtract(viewPoint));
return (winding > 0);
};
GameLib.D3.Vector3.normal = function (u, v, w) {
var vv = v.copy();
var wv = w.copy();
return vv.subtract(u).cross(wv.subtract(u));
};
GameLib.D3.Vector3.prototype.lookAt = function (at, up) {
var lookAtMatrix = GameLib.D3.Matrix4.lookAt(this, at, up);
this.multiply(lookAtMatrix);
};
GameLib.D3.Vector3.prototype.translate = function (v) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
};
GameLib.D3.Vector3.prototype.squared = function () {
return this.x * this.x + this.y * this.y + this.z * this.z;
};
GameLib.D3.Vector3.prototype.copy = function () {
return new GameLib.D3.Vector3(
this.x,
this.y,
this.z
);
};
GameLib.D3.Vector3.prototype.multiply = function (s) {
if (s instanceof GameLib.D3.Vector3) {
this.x *= s.x;
this.y *= s.y;
this.z *= s.z;
} else if (s instanceof GameLib.D3.Matrix4) {
var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z;
var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z;
var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z;
this.x = x;
this.y = y;
this.z = z;
} else {
console.log("functionality not implemented - please do this");
throw new Error("not implemented");
}
return this;
};
GameLib.D3.Vector3.prototype.dot = function (v) {
return (this.x * v.x) + (this.y * v.y) + (this.z * v.z);
};
GameLib.D3.Vector3.prototype.normalize = function () {
var EPSILON = 0.000001;
var v2 = this.squared();
if (v2 < EPSILON) {
return this; //do nothing for zero vector
}
var invLength = 1 / Math.sqrt(v2);
this.x *= invLength;
this.y *= invLength;
this.z *= invLength;
return this;
};

323
src/game-lib-vector-4.js Normal file
View File

@ -0,0 +1,323 @@
GameLib.D3.Vector4 = function(x, y, z, w) {
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 0;
if (x) {
this.x = x;
}
if (y) {
this.y = y;
}
if (z) {
this.z = z;
}
if (w) {
this.w = w;
}
};
GameLib.D3.Vector4.prototype.translate = function (v) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
};
GameLib.D3.Vector4.prototype.copy = function () {
return new GameLib.D3.Vector4(
this.x,
this.y,
this.z,
this.w
);
};
GameLib.D3.Vector4.prototype.multiply = function (s) {
if (s instanceof GameLib.D3.Vector3) {
this.x *= s.x;
this.y *= s.y;
this.z *= s.z;
} else if (s instanceof GameLib.D3.Matrix4) {
var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z + s.rows[0].w * this.w;
var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z + s.rows[1].w * this.w;
var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z + s.rows[2].w * this.w;
var w = s.rows[3].x * this.x + s.rows[3].y * this.y + s.rows[3].z * this.z + s.rows[3].w * this.w;
this.x = x;
this.y = y;
this.z = z;
this.w = w;
} else {
console.log("functionality not implemented - please do this");
throw new Error("not implemented");
}
};
GameLib.D3.Vector4.prototype.normalize = function () {
// note - leave w untouched
var EPSILON = 0.000001;
var v2 = this.x * this.x + this.y * this.y + this.z * this.z;
if (v2 < EPSILON) {
return this; //do nothing for zero vector
}
var invLength = 1 / Math.sqrt(v2);
this.x *= invLength;
this.y *= invLength;
this.z *= invLength;
return this;
};
GameLib.D3.Vector4.prototype.subtract = function (v) {
if (v instanceof GameLib.D3.Vector3) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
}
if (v instanceof GameLib.D3.Vector4) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
this.w -= v.w;
}
return this;
};
GameLib.D3.Vector4.Points = function () {
this.vectors = [];
};
GameLib.D3.Vector4.Points.prototype.add = function (vector) {
if (vector instanceof GameLib.D3.Vector3) {
vector = new GameLib.D3.Vector4(
vector.x,
vector.y,
vector.z,
1
)
}
if (!vector instanceof GameLib.D3.Vector4) {
console.warn("Vector needs to be of type Vector4");
throw new Error("Vector needs to be of type Vector4");
}
this.vectors.push(vector);
return this;
};
GameLib.D3.Vector4.Points.prototype.copy = function () {
var vectors = [];
for (var i = 0; i < this.vectors.length; i++) {
vectors.push(this.vectors[i].copy());
}
return vectors;
};
GameLib.D3.Vector4.Points.prototype.maximizeXDistance = function (grain) {
// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
var multiplier = 0;
var rotationMatrixY = new GameLib.D3.Matrix4().rotationMatrixY(grain);
var totalRadians = 0;
var backupVectors = this.copy();
var maxXDistance = 0;
for (var i = 0; i < Math.PI * 2; i += grain) {
multiplier++;
for (var j = 0; j < this.vectors.length; j++) {
this.vectors[j] = rotationMatrixY.multiply(this.vectors[j]);
}
var distances = this.distances();
if (distances.x > maxXDistance) {
maxXDistance = distances.x;
totalRadians = multiplier * grain;
}
}
this.vectors = backupVectors;
// console.log("distance: " + maxXDistance + " radians : " + totalRadians);
var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixY(totalRadians);
for (var k = 0; k < this.vectors.length; k++) {
this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
}
// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
};
GameLib.D3.Vector4.Points.prototype.maximizeYDistance = function (grain) {
// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
var multiplier = 0;
var rotationMatrixX = new GameLib.D3.Matrix4().rotationMatrixX(grain);
var totalRadians = 0;
var backupVectors = this.copy();
var maxYDistance = 0;
for (var i = 0; i < Math.PI * 2; i += grain) {
multiplier++;
for (var j = 0; j < this.vectors.length; j++) {
this.vectors[j] = rotationMatrixX.multiply(this.vectors[j]);
}
var distances = this.distances();
if (distances.y > maxYDistance) {
maxYDistance = distances.y;
totalRadians = multiplier * grain;
}
}
this.vectors = backupVectors;
// console.log("distance: " + maxYDistance + " radians : " + totalRadians);
var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixX(totalRadians);
for (var k = 0; k < this.vectors.length; k++) {
this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
}
// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
};
GameLib.D3.Vector4.Points.prototype.lookAt = function (at, up) {
var polyCenter = this.average();
console.log("poly center : " + JSON.stringify(polyCenter));
var lookAtMatrix = new GameLib.D3.Matrix4().lookAt(polyCenter, at, up);
lookAtMatrix.rows[0] = new GameLib.D3.Vector4(1, 0, 0, 0);
lookAtMatrix.rows[1] = new GameLib.D3.Vector4(0, 0, 1, 0);
lookAtMatrix.rows[2] = new GameLib.D3.Vector4(0, 1, 0, 0);
console.log("look at matrix : " + JSON.stringify(lookAtMatrix, null, 2));
for (var i = 0; i < this.vectors.length; i++) {
console.log("vector " + i + " (before): " + JSON.stringify(this.vectors[i]));
this.vectors[i] = lookAtMatrix.multiply(this.vectors[i]);
console.log("vector " + i + " (after) : " + JSON.stringify(this.vectors[i]));
}
};
GameLib.D3.Vector4.Points.prototype.distances = function () {
var minX = this.vectors[0].x;
var minY = this.vectors[0].y;
var minZ = this.vectors[0].z;
var maxX = this.vectors[0].x;
var maxY = this.vectors[0].y;
var maxZ = this.vectors[0].z;
for (var i = 0; i < this.vectors.length; i++) {
if (this.vectors[i].x < minX) {
minX = this.vectors[i].x;
}
if (this.vectors[i].y < minY) {
minY = this.vectors[i].y;
}
if (this.vectors[i].z < minZ) {
minZ = this.vectors[i].z;
}
if (this.vectors[i].x > maxX) {
maxX = this.vectors[i].x;
}
if (this.vectors[i].y > maxY) {
maxY = this.vectors[i].y;
}
if (this.vectors[i].z > maxZ) {
maxZ = this.vectors[i].z;
}
}
return new GameLib.D3.Vector3(
Math.abs(maxX - minX),
Math.abs(maxY - minY),
Math.abs(maxY - minZ)
)
};
GameLib.D3.Vector4.Points.prototype.average = function () {
var averageX = 0;
var averageY = 0;
var averageZ = 0;
for (var i = 0; i < this.vectors.length; i++) {
averageX += this.vectors[i].x;
averageY += this.vectors[i].y;
averageZ += this.vectors[i].z;
}
return new GameLib.D3.Vector3(
averageX / this.vectors.length,
averageY / this.vectors.length,
averageZ / this.vectors.length
);
};
GameLib.D3.Vector4.Points.prototype.negative = function () {
for (var i = 0; i < this.vectors.length; i++) {
this.vectors[i].x *= -1;
this.vectors[i].y *= -1;
this.vectors[i].z *= -1;
}
return this;
};
GameLib.D3.Vector4.Points.prototype.toOrigin = function () {
var distanceFromOrigin = this.average().negative();
for (var i = 0; i < this.vectors.length; i++) {
this.vectors[i].translate(distanceFromOrigin);
}
};

13
src/game-lib-vertex.js Normal file
View File

@ -0,0 +1,13 @@
/**
* The normal gets assigned when the face calculates its normal
* @param position
* @param boneWeights GameLib.D3.BoneWeight[]
* @constructor
*/
GameLib.D3.Vertex = function(
position,
boneWeights
) {
this.position = position;
this.boneWeights = boneWeights;
};

425
src/game-lib-world.js Normal file
View File

@ -0,0 +1,425 @@
/**
* World SuperSet - contains the custom world instance
* @param id
* @param name
* @param engine
* @param gravity
* @param broadphase
* @param solver
* @param rigidBodies
* @constructor
*/
GameLib.D3.World = function(
id,
name,
engine,
gravity,
broadphase,
solver,
rigidBodies
) {
this.id = id;
this.name = name;
if (typeof gravity == 'undefined') {
gravity = new GameLib.D3.Vector3(0, -9.81, 0);
}
this.gravity = gravity;
if (typeof broadphase == 'undefined') {
broadphase = new GameLib.D3.Physics.Broadphase(
null,
'broadPhaseNaive',
GameLib.D3.Physics.BROADPHASE_TYPE_NAIVE
);
}
this.broadphase = broadphase;
if (typeof solver == 'undefined') {
solver = new GameLib.D3.Physics.Solver(
null,
'GSSolver',
GameLib.D3.Physics.GS_SOLVER
);
}
this.solver = solver;
if (typeof rigidBodies == 'undefined') {
rigidBodies = [];
}
this.rigidBodies = rigidBodies;
this.engine = null;
this.worldInstance = null;
/**
* We only set the physics property if we pass it in the constructor,
* because we don't always want the physics object (ex. when we store this world to the API - we also don't then
* want to store the custom worlds - we want to generate them after loading from API)
*/
if (engine) {
this.engine = engine;
this.worldInstance = this.createWorldInstance();
}
};
GameLib.D3.World.prototype.createWorldInstance = function() {
this.engine.isNotCannonThrow();
var customWorld = new this.engine.instance.World();
var cannonBroadphase = null;
customWorld.broadphase = cannonBroadphase;
var cannonSolver = null;
if (this.solver.solverType == GameLib.D3.Physics.SPLIT_SOLVER) {
cannonSolver = new this.engine.instance.SplitSolver();
} else if (this.solver.solverType == GameLib.D3.Physics.GS_SOLVER) {
cannonSolver = new this.engine.instance.GSSolver();
cannonSolver.iterations = this.solver.iterations;
}
customWorld.solver = cannonSolver;
customWorld.gravity.x = this.gravity.x;
customWorld.gravity.y = this.gravity.y;
customWorld.gravity.z = this.gravity.z;
for (var b = 0; b < this.rigidBodies.length; b++) {
var customBody = this.createCustomBody(this.rigidBodies[b]);
//customWorld.AddRigidBody();
}
customWorld.name = this.name;
return customWorld;
};
GameLib.D3.World.prototype.AddShape = function(
shape, // d3.physics.shape
rigidBody,
offset, // vec3
orientation //quaternion
) {
shape.shape = shape;
/**
* TODO:: fix this?
*/
if (this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
var _offset = null;
var _orientation = null;
if(offset != null && typeof offset !== 'undefined') {
_offset = new this.physics.CANNON.Vec3(offset.x, offset.y, offset.z);
}
if(orientation != null && typeof orientation !== 'undefined') {
_orientation = new this.physics.CANNON.Quaternion(orientation.x, orientation.y, orientation.z, orientation.w);
}
rigidBody.bodyObject.addShape(shape.shapeObject, _offset, _orientation);
}
};
GameLib.D3.World.prototype.Wheel = function() {
};
GameLib.D3.World.prototype.CreateRigidVehicle = function(
chassisBody // Physics.RigidBody
) {
var rigidVehicle = new GameLib.D3.Physics.RigidVehicle();
if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
var vehicle = new this.physics.CANNON.RigidVehicle({
chassisBody: chassisBody.bodyObject
});
rigidVehicle.vehicleObject = vehicle;
return rigidVehicle;
}
};
GameLib.D3.World.prototype.CreateRaycastVehicle = function(
chassisBody // Physics.RigidBody
) {
var raycastVehicle = new GameLib.D3.Physics.RaycastVehicle();
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
var vehicle = new this.physics.CANNON.RaycastVehicle({
chassisBody: chassisBody.bodyObject
});
raycastVehicle.vehicleObject = vehicle;
return raycastVehicle;
}
};
GameLib.D3.World.prototype.AddWheelToRigidVehicle = function(
vehicle,
rigidBody,
position,
axis,
direction
) {
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
vehicle.vehicleObject.addWheel({
body: rigidBody.bodyObject,
position: new this.physics.CANNON.Vec3(position.x, position.y, position.z),
axis: new this.physics.CANNON.Vec3(axis.x, axis.y, axis.z),
direction: new this.physics.CANNON.Vec3(direction.x, direction.y, direction.z)
});
}
};
GameLib.D3.World.prototype.AddWheelToRaycastVehicle = function (
vehicle, // physics.raycastvehicle
options // cannon options
) {
if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
vehicle.vehicleObject.addWheel(options);
} else {
console.log("function for engine not implemented");
}
};
GameLib.D3.World.prototype.CreateTriMeshShape = function(
vertices, // flat list of floats
indices // flat list of floats
) {
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Trimesh(vertices, indices), GameLib.D3.Physics.SHAPE_TYPE_TRIMESH);
}
};
GameLib.D3.World.prototype.CreateSphereShape = function (
radius
) {
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Sphere(radius), GameLib.D3.Physics.SHAPE_TYPE_SPHERE);
}
};
GameLib.D3.World.prototype.CreateBoxShape = function(
halfExtensions // vec3
) {
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Box(new this.physics.CANNON.Vec3(halfExtensions.x, halfExtensions.y, halfExtensions.z)), GameLib.D3.Physics.SHAPE_TYPE_BOX);
}
};
GameLib.D3.World.prototype.CreateCylinderShape = function(
radiusTop,
radiusBottom,
height,
numSegments
) {
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Cylinder(radiusTop, radiusBottom, height, numSegments), GameLib.D3.Physics.SHAPE_TYPE_CYLINDER);
}
};
GameLib.D3.World.prototype.AddRigidBody = function(
rigidBody // Physics.RigidBody
) {
if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
this.worldObject.addBody(rigidBody.bodyObject);
}
};
GameLib.D3.World.prototype.AddVehicle = function(
vehicle // note: physics.vehicle
) {
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
vehicle.vehicleObject.addToWorld(this.worldObject);
}
};
GameLib.D3.World.prototype.Step = function(
timeStep
) {
if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
// todo: figure out, why this call to internal step is more stable for trimesh collisions.....
//this.worldObject.internalStep(timeStep);
//return;
var now = performance.now() / 1000;
if(!this.lastCallTime){
// last call time not saved, cant guess elapsed time. Take a simple step.
this.worldObject.step(timeStep);
this.lastCallTime = now;
return;
}
var timeSinceLastCall = now - this.lastCallTime;
this.worldObject.step(timeStep, timeSinceLastCall);
this.lastCallTime = now;
}
};
GameLib.D3.World.prototype.GetIndexedVertices = function(
triangleMeshShape
) {
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
return {
vertices : triangleMeshShape.vertices,
indices : triangleMeshShape.indices
};
} else {
// todo: implement this for other physics engines.
return null;
}
};
GameLib.D3.World.prototype.GenerateWireframeViewMesh = function(
triangleMeshShape,
normalLength,
scale,
opacity,
wireframeColor
) {
var geometryTHREE = new THREE.Geometry();
var wireframeTHREEMesh = new THREE.Mesh
(
geometryTHREE,
new THREE.MeshBasicMaterial({
color: wireframeColor ? wireframeColor : 0xfefefe,
wireframe: true,
opacity: opacity ? opacity : 0.5
})
);
var data = this.GetIndexedVertices(triangleMeshShape);
for(var i = 0, l = data.vertices.length / 3; i < l; i++) {
geometryTHREE.vertices.push(new THREE.Vector3(data.vertices[i * 3], data.vertices[i * 3 + 1], data.vertices[i * 3 + 2]));
}
for(var i = 0, l = data.indices.length / 3; i < l; i++) {
var i0 = data.indices[i * 3];
var i1 = data.indices[i * 3 + 1];
var i2 = data.indices[i * 3 + 2];
geometryTHREE.faces.push(new THREE.Face3(i0, i1, i2));
// Create debug view for normals
// Center point on the mesh itself
var centroid = new THREE.Vector3()
.add(geometryTHREE.vertices[i0])
.add(geometryTHREE.vertices[i1])
.add(geometryTHREE.vertices[i2])
.divideScalar(3);
var normal = null;
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
var normal = new this.physics.CANNON.Vec3();
triangleMeshShape.getNormal(i, normal);
} else {
// todo: calculate the normal for v0, v1 & v2 here.
}
var arrow = new THREE.ArrowHelper(new THREE.Vector3(normal.x, normal.y, normal.z), centroid, normalLength, new THREE.Color(normal.x, normal.y, normal.z));
wireframeTHREEMesh.add( arrow );
}
wireframeTHREEMesh.scale.x = scale.x;
wireframeTHREEMesh.scale.y = scale.y;
wireframeTHREEMesh.scale.z = scale.z;
return wireframeTHREEMesh;
};
GameLib.D3.World.prototype.GenerateTriangleCollisionMesh = function(
threeMesh,
mass, // default = 0
friction, // default = 10
createCollisionSubMeshes, // boolean. default = false
facesPerSubsection, // int. default = 0
subsectionsToMerge // int. default = 0
) {
var processedFaces = 0;
var facesPerSubSection = facesPerSubsection || 0;
var subMeshesToMerge = subsectionsToMerge || 0;
var totalAmtFaces = threeMesh.geometry.faces.length;
var facesToProcess = createCollisionSubMeshes ? (subMeshesToMerge * facesPerSubSection) : totalAmtFaces;
var pairs = []; // output
var vertices = [];
var indicies = [];
for(var i = 0; i <= totalAmtFaces; i++) {
if(processedFaces == facesToProcess || i == totalAmtFaces) {
var body = null;
if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
var meshShape = new this.physics.CANNON.Trimesh(vertices, indicies);
meshShape.setScale(new this.physics.CANNON.Vec3(threeMesh.scale.x, threeMesh.scale.y, threeMesh.scale.z));
meshShape.updateAABB();
meshShape.updateNormals();
meshShape.updateEdges();
meshShape.updateBoundingSphereRadius();
meshShape.updateTree();
body = new this.physics.CANNON.Body({ mass: mass ? mass : 0, friction: friction ? friction : 10 });
body.addShape(meshShape);
} else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_AMMO) {
} else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_GOBLIN) {
}
pairs.push({
threeObject : createCollisionSubMeshes ? null : threeMesh,
physicsObject : body
});
vertices = [];
indicies = [];
processedFaces = 0;
if(i == totalAmtFaces) {
return pairs;
}
}
var face = threeMesh.geometry.faces[i];
indicies.push(indicies.length);
indicies.push(indicies.length);
indicies.push(indicies.length);
var v0 = threeMesh.geometry.vertices[face.a];
var v1 = threeMesh.geometry.vertices[face.b];
var v2 = threeMesh.geometry.vertices[face.c];
vertices.push(v0.x, v0.y, v0.z);
vertices.push(v1.x, v1.y, v1.z);
vertices.push(v2.x, v2.y, v2.z);
processedFaces++;
}
};

3
src/game-lib-z.js Normal file
View File

@ -0,0 +1,3 @@
if (typeof module !== 'undefined') {
module.exports = GameLib;
}

94
src/index.js Normal file
View File

@ -0,0 +1,94 @@
if (typeof GameLib === 'undefined') {
function GameLib() {}
}
if (typeof GameLib.D3 === 'undefined') {
GameLib.D3 = function() {};
}
if (typeof require != 'undefined') {
GameLib.D3.Bone = require('./game-lib-bone.js');
GameLib.D3.BoneWeight = require('./game-lib-bone-weight');
GameLib.D3.Broadphase = require('./game-lib-broadphase');
GameLib.D3.Color = require('./game-lib-color');
GameLib.D3.FlyControls = require('./game-lib-fly-controls');
GameLib.D3.Engine = require('./game-lib-engine');
GameLib.D3.Game = require('./game-lib-game');
GameLib.D3.Heightmap = require('./game-lib-heightmap');
GameLib.D3.Image = require('./game-lib-image');
GameLib.D3.Light = require('./game-lib-light');
GameLib.D3.Material = require('./game-lib-material');
GameLib.D3.Matrix3 = require('./game-lib-matrix-3');
GameLib.D3.Matrix4 = require('./game-lib-matrix-4');
GameLib.D3.Mesh = require('./game-lib-mesh');
GameLib.D3.Physics = require('./game-lib-physics');
GameLib.D3.PolyVertex = require('./game-lib-poly-vertex');
GameLib.D3.RaycastVehicle = require('./game-lib-raycast-vehicle');
GameLib.D3.RigidBody = require('./game-lib-rigid-body');
GameLib.D3.RigidBodyVehicle = require('./game-lib-rigid-body-vehicle');
GameLib.D3.Scene = require('./game-lib-scene');
GameLib.D3.Shape = require('./game-lib-shape');
GameLib.D3.Skeleton = require('./game-lib-skeleton');
GameLib.D3.SkyBox = require('./game-lib-sky-box');
GameLib.D3.Solver = require('./game-lib-solver');
GameLib.D3.Texture = require('./game-lib-texture');
GameLib.D3.TriangleEdge = require('./game-lib-triangle-edge');
GameLib.D3.TriangleFace = require('./game-lib-triangle-face');
GameLib.D3.Vector2 = require('./game-lib-vector-2');
GameLib.D3.Vector3 = require('./game-lib-vector-3');
GameLib.D3.Vector4 = require('./game-lib-vector-4');
GameLib.D3.Vector4.Points = require('./game-lib-vector-4-points');
GameLib.D3.Vertex = require('./game-lib-vertex');
GameLib.D3.World = require('./game-lib-world');
}
if (typeof module != 'undefined') {
module.exports = GameLib;
}
if (typeof module != 'undefined') {
module.exports = GameLib;
}

144
test/test.gameLib.js Normal file
View File

@ -0,0 +1,144 @@
var chai = require('chai'),
sinon = require("sinon"),
sinonChai = require("sinon-chai"),
config = require('../config.js'),
assert = chai.assert,
GameLib = require('../build/game-lib'),
CANNON = require('cannon'),
THREE = require('three');
chai.use(sinonChai);
describe('GameLib object creation', function(){
this.timeout(0);
before(function(){
});
after(function(){
});
beforeEach(function(done) {
done();
});
afterEach(function(done){
done();
});
it('Should create a Bone object', function (done) {
var bone = new GameLib.D3.Bone(
null,
1,
'test bone 1',
[2, 3, 4]
);
assert(bone.position instanceof GameLib.D3.Vector3);
assert(bone.rotation instanceof GameLib.D3.Vector3);
assert(bone.scale instanceof GameLib.D3.Vector3);
assert(bone.up instanceof GameLib.D3.Vector3);
assert(bone.quaternion instanceof GameLib.D3.Vector4);
assert(bone.parentBoneId == null);
assert.deepEqual(bone.childBoneIds, [2,3,4]);
done();
});
it('Should create a BoneWeight object', function (done) {
var boneWeight = new GameLib.D3.BoneWeight(
1,
0.5
);
assert(boneWeight.boneIndex == 1);
assert(boneWeight.weight == 0.5);
done();
});
it('Should create a Broadphase object', function (done) {
var engine = new GameLib.D3.Engine(
GameLib.D3.Engine.ENGINE_TYPE_CANNON,
CANNON
);
assert(engine.engineType == GameLib.D3.Engine.ENGINE_TYPE_CANNON);
assert(engine.instance instanceof Object);
var broadphase = new GameLib.D3.Broadphase(
null,
'broad-phase',
GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE,
engine,
true
);
assert(broadphase.id == null);
assert(broadphase.instance instanceof CANNON.NaiveBroadphase);
assert(broadphase.engine instanceof GameLib.D3.Engine);
assert(broadphase.name == 'broad-phase');
assert(broadphase.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE);
done();
});
it('Should create a Color object', function (done) {
var color = new GameLib.D3.Color(
0.1,
0.2,
0.3,
0.4
);
assert(color.r == 0.1);
assert(color.g == 0.2);
assert(color.b == 0.3);
assert(color.a == 0.4);
done();
});
it('Should create a Color object', function (done) {
var color = new GameLib.D3.Color(
0.1,
0.2,
0.3,
0.4
);
assert(color.r == 0.1);
assert(color.g == 0.2);
assert(color.b == 0.3);
assert(color.a == 0.4);
done();
});
it('Should create an Engine object', function (done) {
var engine = new GameLib.D3.Engine(
GameLib.D3.Engine.ENGINE_TYPE_CANNON,
CANNON
);
assert(engine.engineType == GameLib.D3.Engine.ENGINE_TYPE_CANNON);
assert(engine.instance instanceof Object);
done();
});
it('Should create a FlyControls object', function (done) {
console.log("Cannot test FlyControls server side");
done();
});
});