scenejs_on_rails 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  3. data/app/controllers/scenejs_controller.rb +53 -0
  4. data/app/views/scenejs/get_scenejs_data.html.erb +3 -0
  5. data/lib/scenejs_on_rails.rb +1 -1
  6. data/lib/scenejs_on_rails/rails.rb +5 -0
  7. data/lib/scenejs_on_rails/version.rb +1 -1
  8. data/vendor/assets/javascripts/scenejs.js +17307 -0
  9. data/vendor/assets/javascripts/scenejs_extras/gui.js +478 -0
  10. data/vendor/assets/javascripts/scenejs_extras/gui/README.md +4 -0
  11. data/vendor/assets/javascripts/scenejs_extras/gui/dat.gui.min.js +94 -0
  12. data/vendor/assets/javascripts/scenejs_extras/gui/gui.js +385 -0
  13. data/vendor/assets/javascripts/scenejs_lib/cityBuilder.js +457 -0
  14. data/vendor/assets/javascripts/scenejs_lib/dat.gui.min.js +94 -0
  15. data/vendor/assets/javascripts/scenejs_lib/gl-matrix-min.js +28 -0
  16. data/vendor/assets/javascripts/scenejs_lib/gl-matrix.js +4078 -0
  17. data/vendor/assets/javascripts/scenejs_lib/require.js +36 -0
  18. data/vendor/assets/javascripts/scenejs_lib/requireConfig.js +18 -0
  19. data/vendor/assets/javascripts/scenejs_lib/requireWrapperEnd.js +1 -0
  20. data/vendor/assets/javascripts/scenejs_lib/requireWrapperStart.js +2 -0
  21. data/vendor/assets/javascripts/scenejs_lib/stats.min.js +6 -0
  22. data/vendor/assets/javascripts/scenejs_lib/sylvester.js +1 -0
  23. data/vendor/assets/javascripts/scenejs_lib/webgl-debug-utils.js +839 -0
  24. data/vendor/assets/javascripts/scenejs_plugins/geometry/boundary.js +59 -0
  25. data/vendor/assets/javascripts/scenejs_plugins/geometry/box.js +72 -0
  26. data/vendor/assets/javascripts/scenejs_plugins/geometry/plane.js +126 -0
  27. data/vendor/assets/javascripts/scenejs_plugins/geometry/quad.js +37 -0
  28. data/vendor/assets/javascripts/scenejs_plugins/geometry/skybox.js +86 -0
  29. data/vendor/assets/javascripts/scenejs_plugins/geometry/sphere.js +82 -0
  30. data/vendor/assets/javascripts/scenejs_plugins/geometry/teapot.js +5853 -0
  31. data/vendor/assets/javascripts/scenejs_plugins/geometry/torus.js +139 -0
  32. data/vendor/assets/javascripts/scenejs_plugins/geometry/vectorText.js +1499 -0
  33. data/vendor/assets/javascripts/scenejs_plugins/geometry/wobblyBox.js +44 -0
  34. data/vendor/assets/javascripts/scenejs_plugins/lib/canvas2image.js +198 -0
  35. data/vendor/assets/javascripts/scenejs_plugins/lib/frustum/frustumCullEngine.js +810 -0
  36. data/vendor/assets/javascripts/scenejs_plugins/lib/frustum/frustumCullSystem.js +185 -0
  37. data/vendor/assets/javascripts/scenejs_plugins/lib/frustum/frustumCullSystemPool.js +174 -0
  38. data/vendor/assets/javascripts/scenejs_plugins/lib/frustum/frustumCullWorker.js +142 -0
  39. data/vendor/assets/javascripts/scenejs_plugins/lib/gl-matrix-min.js +28 -0
  40. data/vendor/assets/javascripts/scenejs_plugins/lib/jquery-1.8.3.min.js +2 -0
  41. data/vendor/assets/javascripts/scenejs_plugins/lib/k3d.js +1029 -0
  42. data/vendor/assets/javascripts/scenejs_plugins/lib/physics/jiglib.all.min.js +3 -0
  43. data/vendor/assets/javascripts/scenejs_plugins/lib/physics/physics.js +223 -0
  44. data/vendor/assets/javascripts/scenejs_plugins/lib/physics/worker.js +330 -0
  45. data/vendor/assets/javascripts/scenejs_plugins/node/alpha/orbitTracking.js +295 -0
  46. data/vendor/assets/javascripts/scenejs_plugins/node/alpha/orbitTrackingTarget.js +43 -0
  47. data/vendor/assets/javascripts/scenejs_plugins/node/backgrounds/gradient.js +148 -0
  48. data/vendor/assets/javascripts/scenejs_plugins/node/cameras/orbit.js +172 -0
  49. data/vendor/assets/javascripts/scenejs_plugins/node/cameras/pickFlyOrbit.js +409 -0
  50. data/vendor/assets/javascripts/scenejs_plugins/node/canvas/capture.js +107 -0
  51. data/vendor/assets/javascripts/scenejs_plugins/node/demos/color.js +30 -0
  52. data/vendor/assets/javascripts/scenejs_plugins/node/demos/redTeapot.js +52 -0
  53. data/vendor/assets/javascripts/scenejs_plugins/node/demos/spinningTeapot.js +43 -0
  54. data/vendor/assets/javascripts/scenejs_plugins/node/effects/crt.js +36 -0
  55. data/vendor/assets/javascripts/scenejs_plugins/node/effects/fog.js +159 -0
  56. data/vendor/assets/javascripts/scenejs_plugins/node/effects/snowyPeaks.js +50 -0
  57. data/vendor/assets/javascripts/scenejs_plugins/node/effects/wobble.js +42 -0
  58. data/vendor/assets/javascripts/scenejs_plugins/node/effects/xray.js +126 -0
  59. data/vendor/assets/javascripts/scenejs_plugins/node/frustum/body.js +112 -0
  60. data/vendor/assets/javascripts/scenejs_plugins/node/frustum/cull.js +42 -0
  61. data/vendor/assets/javascripts/scenejs_plugins/node/frustum/lod.js +125 -0
  62. data/vendor/assets/javascripts/scenejs_plugins/node/heightmaps/custom.js +185 -0
  63. data/vendor/assets/javascripts/scenejs_plugins/node/import/3ds.js +91 -0
  64. data/vendor/assets/javascripts/scenejs_plugins/node/import/md2.js +139 -0
  65. data/vendor/assets/javascripts/scenejs_plugins/node/import/obj.js +100 -0
  66. data/vendor/assets/javascripts/scenejs_plugins/node/objects/buildings/building.js +352 -0
  67. data/vendor/assets/javascripts/scenejs_plugins/node/objects/buildings/building/HighRiseGlass.jpg +0 -0
  68. data/vendor/assets/javascripts/scenejs_plugins/node/objects/buildings/building/HighRiseGlassSpecular.jpg +0 -0
  69. data/vendor/assets/javascripts/scenejs_plugins/node/objects/buildings/building/highrise-windows.jpg +0 -0
  70. data/vendor/assets/javascripts/scenejs_plugins/node/objects/buildings/building/pixelcity_windows7.jpg +0 -0
  71. data/vendor/assets/javascripts/scenejs_plugins/node/objects/buildings/city.js +26 -0
  72. data/vendor/assets/javascripts/scenejs_plugins/node/objects/plants/ghostTree.js +387 -0
  73. data/vendor/assets/javascripts/scenejs_plugins/node/objects/space/planets/earth.js +168 -0
  74. data/vendor/assets/javascripts/scenejs_plugins/node/objects/space/planets/earth/earth-lights.gif +0 -0
  75. data/vendor/assets/javascripts/scenejs_plugins/node/objects/space/planets/earth/earth-specular.gif +0 -0
  76. data/vendor/assets/javascripts/scenejs_plugins/node/objects/space/planets/earth/earth-specular.jpg +0 -0
  77. data/vendor/assets/javascripts/scenejs_plugins/node/objects/space/planets/earth/earth.jpg +0 -0
  78. data/vendor/assets/javascripts/scenejs_plugins/node/objects/space/planets/earth/earthbump.jpg +0 -0
  79. data/vendor/assets/javascripts/scenejs_plugins/node/objects/space/planets/earth/earthclouds.jpg +0 -0
  80. data/vendor/assets/javascripts/scenejs_plugins/node/objects/toys/drinkingBird.js +632 -0
  81. data/vendor/assets/javascripts/scenejs_plugins/node/objects/vehicles/tank.js +77670 -0
  82. data/vendor/assets/javascripts/scenejs_plugins/node/objects/vehicles/tank.js~ +77636 -0
  83. data/vendor/assets/javascripts/scenejs_plugins/node/physics/body.js +85 -0
  84. data/vendor/assets/javascripts/scenejs_plugins/node/physics/box.js +30 -0
  85. data/vendor/assets/javascripts/scenejs_plugins/node/physics/material.js +35 -0
  86. data/vendor/assets/javascripts/scenejs_plugins/node/physics/plane.js +47 -0
  87. data/vendor/assets/javascripts/scenejs_plugins/node/physics/sphere.js +32 -0
  88. data/vendor/assets/javascripts/scenejs_plugins/node/physics/system.js +44 -0
  89. data/vendor/assets/javascripts/scenejs_plugins/node/physics/teapot.js +29 -0
  90. data/vendor/assets/javascripts/scenejs_plugins/node/prims/boundary.js +73 -0
  91. data/vendor/assets/javascripts/scenejs_plugins/node/prims/box.js +87 -0
  92. data/vendor/assets/javascripts/scenejs_plugins/node/prims/cylinder.js +186 -0
  93. data/vendor/assets/javascripts/scenejs_plugins/node/prims/grid.js +47 -0
  94. data/vendor/assets/javascripts/scenejs_plugins/node/prims/plane.js +137 -0
  95. data/vendor/assets/javascripts/scenejs_plugins/node/prims/quad.js +43 -0
  96. data/vendor/assets/javascripts/scenejs_plugins/node/prims/sphere.js +107 -0
  97. data/vendor/assets/javascripts/scenejs_plugins/node/prims/teapot.js +5846 -0
  98. data/vendor/assets/javascripts/scenejs_plugins/node/prims/torus.js +149 -0
  99. data/vendor/assets/javascripts/scenejs_plugins/node/prims/vectorText.js +1508 -0
  100. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/clouds.js +19 -0
  101. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/cloudySea.js +19 -0
  102. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/custom.js +150 -0
  103. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/grimmNight.js +19 -0
  104. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/interstellarClouds.js +19 -0
  105. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/miramarClouds.js +19 -0
  106. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/stormyDays.js +19 -0
  107. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/textures/clouds.jpg +0 -0
  108. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/textures/cloudySea.jpg +0 -0
  109. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/textures/grimmNight.jpg +0 -0
  110. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/textures/interstellarClouds.jpg +0 -0
  111. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/textures/miramarClouds.jpg +0 -0
  112. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/textures/stormyDays.jpg +0 -0
  113. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/textures/violentDays.jpg +0 -0
  114. data/vendor/assets/javascripts/scenejs_plugins/node/skyboxes/violentDays.js +19 -0
  115. data/vendor/assets/javascripts/scenejs_plugins/texture/image.js +67 -0
  116. data/vendor/assets/javascripts/scenejs_plugins/texture/video.js +105 -0
  117. metadata +113 -1
@@ -0,0 +1,44 @@
1
+ SceneJS.Plugins.addPlugin(
2
+
3
+ "geometry",
4
+
5
+ "wobblyBox",
6
+
7
+ new (function () {
8
+
9
+ this.getSource = function () {
10
+ var publish;
11
+ return {
12
+ subscribe:function (fn) {
13
+ publish = fn;
14
+ },
15
+ configure:function (cfg) {
16
+ publish(build(cfg));
17
+ }
18
+ };
19
+ };
20
+
21
+ function build (cfg) {
22
+ var randomFactor = cfg.randomFactor;
23
+ return {
24
+ primitive:"triangles", // Geometry only uses this on create, ignores on update
25
+ positions:new Float32Array(randomize([ 5, 5, 5, -5, 5, 5, -5, -5, 5, 5, -5, 5, 5, 5, 5, 5, -5, 5, 5, -5, -5, 5, 5, -5, 5, 5, 5, 5, 5, -5, -5, 5, -5, -5, 5, 5, -5, 5, 5, -5, 5, -5, -5, -5, -5, -5, -5, 5, -5, -5, -5, 5, -5, -5, 5, -5, 5, -5, -5, 5, 5, -5, -5, -5, -5, -5, -5, 5, -5, 5, 5, -5], randomFactor)),
26
+ normals:new Float32Array(randomize([ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1], randomFactor)),
27
+ uv:new Float32Array(randomize([ 5, 5, 0, 5, 0, 0, 5, 0, 0, 5, 0, 0, 5, 0, 5, 5, 5, 0, 5, 5, 0, 5, 0, 0, 5, 5, 0, 5, 0, 0, 5, 0, 0, 0, 5, 0, 5, 5, 0, 5, 0, 0, 5, 0, 5, 5, 0, 5], randomFactor)),
28
+ uv2:null,
29
+ indices:new Uint16Array([ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23])
30
+ };
31
+ }
32
+
33
+ function randomize (arry, randomFactor) {
34
+ if (randomFactor == 0) {
35
+ return arry;
36
+ }
37
+ var halfRandomFactor = randomFactor / 2.0;
38
+ for (var i = 0, len = arry.length; i < len; i++) {
39
+ arry[i] += (Math.random() * randomFactor) - halfRandomFactor;
40
+ }
41
+ return arry;
42
+ }
43
+
44
+ })());
@@ -0,0 +1,198 @@
1
+ /*
2
+ * Canvas2Image v0.1
3
+ * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
4
+ * MIT License [http://www.opensource.org/licenses/mit-license.php]
5
+ */
6
+
7
+ var Canvas2Image = (function() {
8
+ // check if we have canvas support
9
+ var oCanvas = document.createElement("canvas"),
10
+ sc = String.fromCharCode,
11
+ strDownloadMime = "image/octet-stream",
12
+ bReplaceDownloadMime = false;
13
+
14
+ // no canvas, bail out.
15
+ if (!oCanvas.getContext) {
16
+ return {
17
+ saveAsBMP : function(){},
18
+ saveAsPNG : function(){},
19
+ saveAsJPEG : function(){}
20
+ }
21
+ }
22
+
23
+ var bHasImageData = !!(oCanvas.getContext("2d").getImageData),
24
+ bHasDataURL = !!(oCanvas.toDataURL),
25
+ bHasBase64 = !!(window.btoa);
26
+
27
+ // ok, we're good
28
+ var readCanvasData = function(oCanvas) {
29
+ var iWidth = parseInt(oCanvas.width),
30
+ iHeight = parseInt(oCanvas.height);
31
+ return oCanvas.getContext("2d").getImageData(0,0,iWidth,iHeight);
32
+ }
33
+
34
+ // base64 encodes either a string or an array of charcodes
35
+ var encodeData = function(data) {
36
+ var i, aData, strData = "";
37
+
38
+ if (typeof data == "string") {
39
+ strData = data;
40
+ } else {
41
+ aData = data;
42
+ for (i = 0; i < aData.length; i++) {
43
+ strData += sc(aData[i]);
44
+ }
45
+ }
46
+ return btoa(strData);
47
+ }
48
+
49
+ // creates a base64 encoded string containing BMP data takes an imagedata object as argument
50
+ var createBMP = function(oData) {
51
+ var strHeader = '',
52
+ iWidth = oData.width,
53
+ iHeight = oData.height;
54
+
55
+ strHeader += 'BM';
56
+
57
+ var iFileSize = iWidth*iHeight*4 + 54; // total header size = 54 bytes
58
+ strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
59
+ strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
60
+ strHeader += sc(iFileSize % 256); iFileSize = Math.floor(iFileSize / 256);
61
+ strHeader += sc(iFileSize % 256);
62
+
63
+ strHeader += sc(0, 0, 0, 0, 54, 0, 0, 0); // data offset
64
+ strHeader += sc(40, 0, 0, 0); // info header size
65
+
66
+ var iImageWidth = iWidth;
67
+ strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
68
+ strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
69
+ strHeader += sc(iImageWidth % 256); iImageWidth = Math.floor(iImageWidth / 256);
70
+ strHeader += sc(iImageWidth % 256);
71
+
72
+ var iImageHeight = iHeight;
73
+ strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
74
+ strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
75
+ strHeader += sc(iImageHeight % 256); iImageHeight = Math.floor(iImageHeight / 256);
76
+ strHeader += sc(iImageHeight % 256);
77
+
78
+ strHeader += sc(1, 0, 32, 0); // num of planes & num of bits per pixel
79
+ strHeader += sc(0, 0, 0, 0); // compression = none
80
+
81
+ var iDataSize = iWidth*iHeight*4;
82
+ strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
83
+ strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
84
+ strHeader += sc(iDataSize % 256); iDataSize = Math.floor(iDataSize / 256);
85
+ strHeader += sc(iDataSize % 256);
86
+
87
+ strHeader += sc(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); // these bytes are not used
88
+
89
+ var aImgData = oData.data,
90
+ strPixelData = "",
91
+ c, x, y = iHeight,
92
+ iOffsetX, iOffsetY, strPixelRow;
93
+
94
+ do {
95
+ iOffsetY = iWidth*(y-1)*4;
96
+ strPixelRow = "";
97
+ for (x = 0; x < iWidth; x++) {
98
+ iOffsetX = 4*x;
99
+ strPixelRow += sc(
100
+ aImgData[iOffsetY + iOffsetX + 2], // B
101
+ aImgData[iOffsetY + iOffsetX + 1], // G
102
+ aImgData[iOffsetY + iOffsetX], // R
103
+ aImgData[iOffsetY + iOffsetX + 3] // A
104
+ );
105
+ }
106
+ strPixelData += strPixelRow;
107
+ } while (--y);
108
+
109
+ return encodeData(strHeader + strPixelData);
110
+ }
111
+
112
+ // sends the generated file to the client
113
+ var saveFile = function(strData) {
114
+ if (!window.open(strData)) {
115
+ document.location.href = strData;
116
+ }
117
+ }
118
+
119
+ var makeDataURI = function(strData, strMime) {
120
+ return "data:" + strMime + ";base64," + strData;
121
+ }
122
+
123
+ // generates a <img> object containing the imagedata
124
+ var makeImageObject = function(strSource) {
125
+ var oImgElement = document.createElement("img");
126
+ oImgElement.src = strSource;
127
+ return oImgElement;
128
+ }
129
+
130
+ var scaleCanvas = function(oCanvas, iWidth, iHeight) {
131
+ if (iWidth && iHeight) {
132
+ var oSaveCanvas = document.createElement("canvas");
133
+
134
+ oSaveCanvas.width = iWidth;
135
+ oSaveCanvas.height = iHeight;
136
+ oSaveCanvas.style.width = iWidth+"px";
137
+ oSaveCanvas.style.height = iHeight+"px";
138
+
139
+ var oSaveCtx = oSaveCanvas.getContext("2d");
140
+
141
+ oSaveCtx.drawImage(oCanvas, 0, 0, oCanvas.width, oCanvas.height, 0, 0, iWidth, iWidth);
142
+
143
+ return oSaveCanvas;
144
+ }
145
+ return oCanvas;
146
+ }
147
+
148
+ return {
149
+ saveAsPNG : function(oCanvas, bReturnImg, iWidth, iHeight) {
150
+ if (!bHasDataURL) return false;
151
+
152
+ var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
153
+ strMime = "image/png",
154
+ strData = oScaledCanvas.toDataURL(strMime);
155
+
156
+ if (bReturnImg) {
157
+ return makeImageObject(strData);
158
+ } else {
159
+ saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData);
160
+ }
161
+ return true;
162
+ },
163
+
164
+ saveAsJPEG : function(oCanvas, bReturnImg, iWidth, iHeight) {
165
+ if (!bHasDataURL) return false;
166
+
167
+ var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
168
+ strMime = "image/jpeg",
169
+ strData = oScaledCanvas.toDataURL(strMime);
170
+
171
+ // check if browser actually supports jpeg by looking for the mime type in the data uri. if not, return false
172
+ if (strData.indexOf(strMime) != 5) return false;
173
+
174
+ if (bReturnImg) {
175
+ return makeImageObject(strData);
176
+ } else {
177
+ saveFile(bReplaceDownloadMime ? strData.replace(strMime, strDownloadMime) : strData);
178
+ }
179
+ return true;
180
+ },
181
+
182
+ saveAsBMP : function(oCanvas, bReturnImg, iWidth, iHeight) {
183
+ if (!(bHasDataURL && bHasImageData && bHasBase64)) return false;
184
+
185
+ var oScaledCanvas = scaleCanvas(oCanvas, iWidth, iHeight),
186
+ strMime = "image/bmp",
187
+ oData = readCanvasData(oScaledCanvas),
188
+ strImgData = createBMP(oData);
189
+
190
+ if (bReturnImg) {
191
+ return makeImageObject(makeDataURI(strImgData, strMime));
192
+ } else {
193
+ saveFile(makeDataURI(strImgData, strMime));
194
+ }
195
+ return true;
196
+ }
197
+ };
198
+ })();
@@ -0,0 +1,810 @@
1
+ //
2
+ // 3D frustum culling engine
3
+ //
4
+ // Has a view matrix, projection matrix, viewport and
5
+ //
6
+ // This file is supposed to be loaded into a Web Worker, so everything's global
7
+ // and we're not bothering with name spaces etc.
8
+ //
9
+
10
+ var OUTSIDE_FRUSTUM = 0;
11
+ var INTERSECT_FRUSTUM = 1;
12
+ var INSIDE_FRUSTUM = 2;
13
+
14
+ /**
15
+ * A frustum culling engine
16
+ * @param cfg
17
+ * @constructor
18
+ */
19
+ function Engine(cfg) {
20
+
21
+ // The current view matrix
22
+ this._viewMat = identityMat4();
23
+
24
+ // Current projection matrix
25
+ this._projMat = identityMat4();
26
+
27
+ // Current viewport
28
+ this._viewport = [0, 0, 1, 1];
29
+
30
+ // Culling frustum constructed from matrices and viewport
31
+ this._frustum = null;
32
+
33
+ // Set when matrices or viewport reconfigured, causes frustum lazy-rebuild on next integration
34
+ this._frustumDirty = true;
35
+
36
+ // Body map, holds bodies by ID
37
+ this._bodies = {};
38
+
39
+ // Bodies in array for efficient iteration
40
+ this._bodyList = [];
41
+ this._numBodies = 0;
42
+
43
+ // Set when body map updated, causes body list lazy-rebuild on next integration
44
+ this._bodyListDirty = false;
45
+
46
+ // Output array containing updated bodies after each integration
47
+ this._updatedBodies = [];
48
+
49
+ if (cfg) {
50
+ this.setConfigs(cfg);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Configures the engine
56
+ * @param cfg
57
+ * @param {Array(16)} [cfg.viewMat] View matrix
58
+ * @param {Array(16)} [cfg.projMat] Projection matrix
59
+ * @param {Array(4)} [cfg.viewport] Viewport
60
+ */
61
+ Engine.prototype.setConfigs = function (cfg) {
62
+ // Configure view matrix
63
+ if (cfg.viewMat) {
64
+ this._viewMat = cfg.viewMat;
65
+ this._frustumDirty = true;
66
+ }
67
+ // Configure projection matrix
68
+ if (cfg.projMat) {
69
+ this._projMat = cfg.projMat;
70
+ this._frustumDirty = true;
71
+ }
72
+ // Configure viewport
73
+ if (cfg.viewport) {
74
+ this._viewport = cfg.viewport;
75
+ this._frustumDirty = true;
76
+ }
77
+ };
78
+
79
+ /**
80
+ * Adds a body to the engine
81
+ * @param {Number} bodyId Unique body ID
82
+ * @param {*} cfg Body properties
83
+ */
84
+ Engine.prototype.addBody = function (bodyId, cfg) {
85
+ if (this._bodies[bodyId]) {
86
+ throw "Body with this ID already added: " + bodyId;
87
+ }
88
+ this._bodies[bodyId] = new Body(bodyId, cfg);
89
+ this._bodyListDirty = true;
90
+ };
91
+
92
+ /**
93
+ * Updates a body
94
+ * @param {Number} bodyId Unique body ID
95
+ * @param {*} cfg New values for body properties
96
+ */
97
+ Engine.prototype.updateBody = function (bodyId, cfg) {
98
+ var body = this._bodies[bodyId];
99
+ if (!body) {
100
+ throw "Body with this ID not found: " + bodyId;
101
+ }
102
+ body.update(cfg);
103
+ };
104
+
105
+ /**
106
+ * Removes a body that was added with {@link #addBody}
107
+ * @param {Number} bodyId ID of body
108
+ */
109
+ Engine.prototype.removeBody = function (bodyId) {
110
+ delete this._bodies[bodyId];
111
+ this._bodyListDirty = true;
112
+ };
113
+
114
+ /**
115
+ * Finds updates in frustum intersection status for bodies,
116
+ * Returns an array of ststus updates for the bodies in a callback
117
+ * @param {Function(Array,Number)} callback Returns array of {@link Body}s that have changed status,
118
+ * plus length of the array
119
+ */
120
+ Engine.prototype.integrate = function (callback) {
121
+ // Lazy-rebuilds frustum after engine reconfiguration
122
+ if (this._frustumDirty) {
123
+ this._rebuildFrustum();
124
+ }
125
+ // Lazy-rebuilds body list after body map updated
126
+ if (this._bodyListDirty) {
127
+ this._rebuildBodyList();
128
+ }
129
+ var numUpdatedBodies = 0;
130
+ var body;
131
+ var intersect;
132
+ var canvasSize;
133
+
134
+ for (var i = 0; i < this._numBodies; i++) {
135
+ body = this._bodyList[i];
136
+ intersect = -1;
137
+ canvasSize = -1;
138
+ if (body.frustumCull) {
139
+ // Frustum cull this body
140
+ intersect = this._frustum.textAxisBoxIntersection(body);
141
+ if (body.detailCull) {
142
+ // And detail cull
143
+ switch (intersect) {
144
+ case INTERSECT_FRUSTUM:
145
+ case INSIDE_FRUSTUM:
146
+ body.projBox.fromPoints(body.viewBox);
147
+ canvasSize = this._frustum.getProjectedSize(body.projBox);
148
+ break;
149
+ }
150
+ }
151
+ } else {
152
+ // Just detail cull
153
+ body.projBox.fromPoints(body.viewBox);
154
+ canvasSize = this._frustum.getProjectedSize(body.projBox);
155
+ }
156
+
157
+ if (intersect !== body.intersect || canvasSize != body.canvasSize) {
158
+ body.intersect = intersect;
159
+ body.canvasSize = canvasSize;
160
+ this._updatedBodies[numUpdatedBodies++] = body;
161
+ }
162
+ }
163
+ callback(this._updatedBodies, numUpdatedBodies);
164
+ };
165
+
166
+ /**
167
+ * Rebuilds culling frustum from matrices and viewport
168
+ */
169
+ Engine.prototype._rebuildFrustum = function () {
170
+ this._frustum = new Frustum(this._viewMat, this._projMat, this._viewport);
171
+ this._frustumDirty = false;
172
+ };
173
+
174
+ /**
175
+ * Rebuilds body list from body map
176
+ */
177
+ Engine.prototype._rebuildBodyList = function () {
178
+ this._numBodies = 0;
179
+ for (var bodyId in this._bodies) {
180
+ if (this._bodies.hasOwnProperty(bodyId)) {
181
+ this._bodyList[this._numBodies++] = this._bodies[bodyId];
182
+ }
183
+ }
184
+ this._bodyListDirty = false;
185
+ };
186
+
187
+ /**
188
+ * A body in the frustum culling engine
189
+ * @param {Number} bodyId Body ID, unique within the engine
190
+ * @param {*} cfg Body properties
191
+ * @param {*} [cfg.box] Axis-aligned world-space bounding box
192
+ * @param {Array(3)} [cfg.box.min] Axis-aligned bounding box minimum extents
193
+ * @param {Array(3)} [cfg.box.max] Axis-aligned bounding box maximum extents
194
+ * @constructor
195
+ */
196
+ function Body(bodyId, cfg) {
197
+
198
+ /**
199
+ * Unique ID within engine
200
+ * @type {*}
201
+ */
202
+ this.bodyId = bodyId;
203
+
204
+ /**
205
+ * World-space extents
206
+ */
207
+ this.min = cfg.min;
208
+ this.max = cfg.max;
209
+
210
+ /**
211
+ * True when frustum culling is to be performed for this body
212
+ */
213
+ this.frustumCull = cfg.frustumCull != undefined ? cfg.frustumCull : true;
214
+
215
+ /**
216
+ * True when projected canvas size is to be determined for this body
217
+ */
218
+ this.detailCull = cfg.detailCull != undefined ? cfg.detailCull : true;
219
+
220
+ /**
221
+ * View-space extents
222
+ */
223
+ this.viewBox = [
224
+ [this.min[0], this.min[1], this.min[2]],
225
+ [this.max[0], this.min[1], this.min[2]],
226
+ [this.max[0], this.max[1], this.min[2]],
227
+ [this.min[0], this.max[1], this.min[2]],
228
+ [this.min[0], this.min[1], this.max[2]],
229
+ [this.max[0], this.min[1], this.max[2]],
230
+ [this.max[0], this.max[1], this.max[2]],
231
+ [this.min[0], this.max[1], this.max[2]]
232
+ ];
233
+
234
+ /**
235
+ * Projection-space extents
236
+ */
237
+ this.projBox = new Box3();
238
+
239
+ /**
240
+ * Intersection status
241
+ * @type {Number}
242
+ */
243
+ this.intersect = null;
244
+
245
+ /**
246
+ * Projected size
247
+ * @type {Number}
248
+ */
249
+ this.canvasSize = null;
250
+ }
251
+
252
+ Body.prototype.update = function (cfg) {
253
+ // if (cfg.min || cfg.max) {
254
+ // if (cfg.min) {
255
+ // this.min = cfg.min;
256
+ // this.viewBox[0][0] = this.min[0];
257
+ // this.viewBox[0][1] = this.min[1];
258
+ // this.viewBox[0][2] = this.min[2];
259
+ //
260
+ // [this.max[0], this.min[1], this.min[2]],
261
+ // [this.max[0], this.max[1], this.min[2]],
262
+ // [this.min[0], this.max[1], this.min[2]],
263
+ // [this.min[0], this.min[1], this.max[2]],
264
+ // [this.max[0], this.min[1], this.max[2]],
265
+ // [this.max[0], this.max[1], this.max[2]],
266
+ // [this.min[0], this.max[1], this.max[2]]
267
+ // }
268
+ // if (cfg.max) {
269
+ // this.max = cfg.max;
270
+ // }
271
+ // this.viewBox[0][0]
272
+ // [this.min[0], this.min[1], this.min[2]],
273
+ // [this.max[0], this.min[1], this.min[2]],
274
+ // [this.max[0], this.max[1], this.min[2]],
275
+ // [this.min[0], this.max[1], this.min[2]],
276
+ // [this.min[0], this.min[1], this.max[2]],
277
+ // [this.max[0], this.min[1], this.max[2]],
278
+ // [this.max[0], this.max[1], this.max[2]],
279
+ // [this.min[0], this.max[1], this.max[2]]
280
+ // ]
281
+ // ;
282
+ //
283
+ // }
284
+ };
285
+
286
+ function Frustum(viewMat, projMat, viewport) {
287
+
288
+ var m = mat4();
289
+
290
+ mulMat4(projMat, viewMat, m);
291
+
292
+ // cache m indexes
293
+ var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3];
294
+ var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7];
295
+ var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11];
296
+ var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15];
297
+
298
+ //var q = [ m[3], m[7], m[11] ]; just reuse m indexes instead of making new var
299
+ var planes = [
300
+ new FrustumPlane(m3 - m0, m7 - m4, m11 - m8, m15 - m12),
301
+ new FrustumPlane(m3 + m0, m7 + m4, m11 + m8, m15 + m12),
302
+ new FrustumPlane(m3 - m1, m7 - m5, m11 - m9, m15 - m13),
303
+ new FrustumPlane(m3 + m1, m7 + m5, m11 + m9, m15 + m13),
304
+ new FrustumPlane(m3 - m2, m7 - m6, m11 - m10, m15 - m14),
305
+ new FrustumPlane(m3 + m2, m7 + m6, m11 + m10, m15 + m14)
306
+ ];
307
+
308
+ // Resources for LOD
309
+
310
+ var rotVec = [
311
+ getColMat4(viewMat, 0),
312
+ getColMat4(viewMat, 1),
313
+ getColMat4(viewMat, 2)
314
+ ];
315
+
316
+ var scaleVec = [
317
+ lenVec4(rotVec[0]),
318
+ lenVec4(rotVec[1]),
319
+ lenVec4(rotVec[2])
320
+ ];
321
+
322
+ var scaleVecRcp = rcpVec3(scaleVec);
323
+ var sMat = scalingMat4v(scaleVec);
324
+ var sMatInv = scalingMat4v(scaleVecRcp);
325
+
326
+ mulVec4Scalar(rotVec[0], scaleVecRcp[0]);
327
+ mulVec4Scalar(rotVec[1], scaleVecRcp[1]);
328
+ mulVec4Scalar(rotVec[2], scaleVecRcp[2]);
329
+
330
+ var rotMatInverse = identityMat4();
331
+
332
+ setRowMat4(rotMatInverse, 0, rotVec[0]);
333
+ setRowMat4(rotMatInverse, 1, rotVec[1]);
334
+ setRowMat4(rotMatInverse, 2, rotVec[2]);
335
+
336
+ if (!this.matrix) {
337
+ this.matrix = mat4();
338
+ }
339
+
340
+ mulMat4(projMat, viewMat, this.matrix);
341
+
342
+ if (!this.billboardMatrix) {
343
+ this.billboardMatrix = mat4();
344
+ }
345
+
346
+ mulMat4(sMatInv, mulMat4(rotMatInverse, sMat), this.billboardMatrix);
347
+ this.viewport = viewport.slice(0, 4);
348
+
349
+ this.textAxisBoxIntersection = function (box) {
350
+ var ret = INSIDE_FRUSTUM;
351
+ var bminmax = [ box.min, box.max ];
352
+ var plane = null;
353
+ for (var i = 0; i < 6; ++i) {
354
+ plane = planes[i];
355
+ if (((plane.normal[0] * bminmax[plane.testVertex[0]][0]) +
356
+ (plane.normal[1] * bminmax[plane.testVertex[1]][1]) +
357
+ (plane.normal[2] * bminmax[plane.testVertex[2]][2]) +
358
+ (plane.offset)) < 0.0) {
359
+ return OUTSIDE_FRUSTUM;
360
+ }
361
+ if (((plane.normal[0] * bminmax[1 - plane.testVertex[0]][0]) +
362
+ (plane.normal[1] * bminmax[1 - plane.testVertex[1]][1]) +
363
+ (plane.normal[2] * bminmax[1 - plane.testVertex[2]][2]) +
364
+ (plane.offset)) < 0.0) {
365
+ ret = INTERSECT_FRUSTUM;
366
+ }
367
+ }
368
+ return ret;
369
+ };
370
+
371
+ this.getProjectedSize = function (box) {
372
+ var diagVec = mat4();
373
+ subVec3(box.max, box.min, diagVec);
374
+
375
+ var diagSize = lenVec3(diagVec);
376
+
377
+ var size = Math.abs(diagSize);
378
+
379
+ var p0 = [
380
+ (box.min[0] + box.max[0]) * 0.5,
381
+ (box.min[1] + box.max[1]) * 0.5,
382
+ (box.min[2] + box.max[2]) * 0.5,
383
+ 0.0];
384
+
385
+ var halfSize = size * 0.5;
386
+ var p1 = [ -halfSize, 0.0, 0.0, 1.0 ];
387
+ var p2 = [ halfSize, 0.0, 0.0, 1.0 ];
388
+
389
+ p1 = mulMat4v4(this.billboardMatrix, p1);
390
+ p1 = addVec4(p1, p0);
391
+ p1 = projectVec4(mulMat4v4(this.matrix, p1));
392
+
393
+ p2 = mulMat4v4(this.billboardMatrix, p2);
394
+ p2 = addVec4(p2, p0);
395
+ p2 = projectVec4(mulMat4v4(this.matrix, p2));
396
+
397
+ return viewport[2] * Math.abs(p2[0] - p1[0]);
398
+ };
399
+
400
+
401
+ this.getProjectedState = function (modelviewBox) {
402
+ var viewviewBox = transformPoints3(this.matrix, modelviewBox);
403
+
404
+ //var canvasBox = {
405
+ // min: [10000000, 10000000 ],
406
+ // max: [-10000000, -10000000]
407
+ //};
408
+ // separate variables instead of indexing an array
409
+ var canvasBoxMin0 = 10000000, canvasBoxMin1 = 10000000;
410
+ var canvasBoxMax0 = -10000000, canvasBoxMax1 = -10000000;
411
+
412
+ var v, x, y;
413
+
414
+ var arrLen = viewviewBox.length;
415
+ for (var i = 0; i < arrLen; ++i) {
416
+ v = projectVec4(viewviewBox[i]);
417
+ x = v[0];
418
+ y = v[1];
419
+
420
+ if (x < -0.5) {
421
+ x = -0.5;
422
+ }
423
+
424
+ if (y < -0.5) {
425
+ y = -0.5;
426
+ }
427
+
428
+ if (x > 0.5) {
429
+ x = 0.5;
430
+ }
431
+
432
+ if (y > 0.5) {
433
+ y = 0.5;
434
+ }
435
+
436
+
437
+ if (x < canvasBoxMin0) {
438
+ canvasBoxMin0 = x;
439
+ }
440
+ if (y < canvasBoxMin1) {
441
+ canvasBoxMin1 = y;
442
+ }
443
+ if (x > canvasBoxMax0) {
444
+ canvasBoxMax0 = x;
445
+ }
446
+ if (y > canvasBoxMax1) {
447
+ canvasBoxMax1 = y;
448
+ }
449
+ }
450
+
451
+ canvasBoxMin0 += 0.5;
452
+ canvasBoxMin1 += 0.5;
453
+ canvasBoxMax0 += 0.5;
454
+ canvasBoxMax1 += 0.5;
455
+
456
+ // cache viewport indexes
457
+ var viewport2 = viewport[2], viewport3 = viewport[3];
458
+
459
+ canvasBoxMin0 = (canvasBoxMin0 * (viewport2 + 15));
460
+ canvasBoxMin1 = (canvasBoxMin1 * (viewport3 + 15));
461
+ canvasBoxMax0 = (canvasBoxMax0 * (viewport2 + 15));
462
+ canvasBoxMax1 = (canvasBoxMax1 * (viewport3 + 15));
463
+
464
+ var diagCanvasBoxVec = mat4();
465
+ subVec2([canvasBoxMax0, canvasBoxMax1], [canvasBoxMin0, canvasBoxMin1], diagCanvasBoxVec);
466
+ var diagCanvasBoxSize = lenVec2(diagCanvasBoxVec);
467
+
468
+ if (canvasBoxMin0 < 0) {
469
+ canvasBoxMin0 = 0;
470
+ }
471
+ if (canvasBoxMax0 > viewport2) {
472
+ canvasBoxMax0 = viewport2;
473
+ }
474
+
475
+ if (canvasBoxMin1 < 0) {
476
+ canvasBoxMin1 = 0;
477
+ }
478
+ if (canvasBoxMax1 > viewport3) {
479
+ canvasBoxMax1 = viewport3;
480
+ }
481
+ return diagCanvasBoxSize;
482
+ // return {
483
+ // canvasBox:{
484
+ // min:[canvasBoxMin0, canvasBoxMin1 ],
485
+ // max:[canvasBoxMax0, canvasBoxMax1 ]
486
+ // },
487
+ // canvasSize:diagCanvasBoxSize
488
+ // };
489
+ };
490
+ }
491
+
492
+ function mat4() {
493
+ return new Array(16);
494
+ }
495
+
496
+ function mulMat4(a, b, dest) {
497
+
498
+ if (!dest) {
499
+ dest = a;
500
+ }
501
+
502
+ // Cache the matrix values (makes for huge speed increases!)
503
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
504
+ var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
505
+ var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
506
+ var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
507
+
508
+ var b00 = b[0], b01 = b[1], b02 = b[2], b03 = b[3];
509
+ var b10 = b[4], b11 = b[5], b12 = b[6], b13 = b[7];
510
+ var b20 = b[8], b21 = b[9], b22 = b[10], b23 = b[11];
511
+ var b30 = b[12], b31 = b[13], b32 = b[14], b33 = b[15];
512
+
513
+ dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
514
+ dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
515
+ dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
516
+ dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
517
+ dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
518
+ dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
519
+ dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
520
+ dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
521
+ dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
522
+ dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
523
+ dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
524
+ dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
525
+ dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
526
+ dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
527
+ dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
528
+ dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
529
+
530
+ return dest;
531
+ }
532
+
533
+ function FrustumPlane(nx, ny, nz, offset) {
534
+ var s = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz);
535
+ this.normal = [nx * s, ny * s, nz * s];
536
+ this.offset = offset * s;
537
+ this.testVertex = [
538
+ (this.normal[0] >= 0.0) ? (1) : (0),
539
+ (this.normal[1] >= 0.0) ? (1) : (0),
540
+ (this.normal[2] >= 0.0) ? (1) : (0)];
541
+ }
542
+
543
+ function getColMat4(m, c) {
544
+ var i = c * 4;
545
+ return [m[i], m[i + 1], m[i + 2], m[i + 3]];
546
+ }
547
+
548
+ function lenVec4(v) {
549
+ return Math.sqrt(sqLenVec4(v));
550
+ }
551
+
552
+ function sqLenVec4(v) {
553
+ return dotVec4(v, v);
554
+ }
555
+
556
+ function dotVec4(u, v) {
557
+ return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2] + u[3] * v[3]);
558
+ }
559
+
560
+ function rcpVec3(v, dest) {
561
+ return divScalarVec3(1.0, v, dest);
562
+ }
563
+
564
+ function divScalarVec3(s, v, dest) {
565
+ if (!dest) {
566
+ dest = v;
567
+ }
568
+ dest[0] = s / v[0];
569
+ dest[1] = s / v[1];
570
+ dest[2] = s / v[2];
571
+ return dest;
572
+ }
573
+
574
+ function scalingMat4v(v) {
575
+ var m = identityMat4();
576
+ m[0] = v[0];
577
+ m[5] = v[1];
578
+ m[10] = v[2];
579
+ return m;
580
+ }
581
+
582
+ function identityMat4() {
583
+ return diagonalMat4v([1.0, 1.0, 1.0, 1.0]);
584
+ }
585
+
586
+ function diagonalMat4v(v) {
587
+ return [
588
+ v[0], 0.0, 0.0, 0.0,
589
+ 0.0, v[1], 0.0, 0.0,
590
+ 0.0, 0.0, v[2], 0.0,
591
+ 0.0, 0.0, 0.0, v[3]
592
+ ];
593
+ }
594
+
595
+ function mulVec4Scalar(v, s, dest) {
596
+ if (!dest) {
597
+ dest = v;
598
+ }
599
+ dest[0] = v[0] * s;
600
+ dest[1] = v[1] * s;
601
+ dest[2] = v[2] * s;
602
+ dest[3] = v[3] * s;
603
+ return dest;
604
+ }
605
+
606
+ function setRowMat4(m, r, v) {
607
+ m[r] = v[0];
608
+ m[r + 4] = v[1];
609
+ m[r + 8] = v[2];
610
+ m[r + 12] = v[3];
611
+ }
612
+
613
+ function subVec3(u, v, dest) {
614
+ if (!dest) {
615
+ dest = u;
616
+ }
617
+ dest[0] = u[0] - v[0];
618
+ dest[1] = u[1] - v[1];
619
+ dest[2] = u[2] - v[2];
620
+ return dest;
621
+ }
622
+
623
+ function lenVec3(v) {
624
+ return Math.sqrt(sqLenVec3(v));
625
+ }
626
+
627
+ function mulMat4v4(m, v) {
628
+ var v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
629
+
630
+ return [
631
+ m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12] * v3,
632
+ m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13] * v3,
633
+ m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14] * v3,
634
+ m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15] * v3
635
+ ];
636
+ }
637
+
638
+ function sqLenVec3(v) {
639
+ return dotVector3(v, v);
640
+ }
641
+
642
+ function dotVector3(u, v) {
643
+ return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]);
644
+ }
645
+
646
+ function addVec4(u, v, dest) {
647
+ if (!dest) {
648
+ dest = u;
649
+ }
650
+ dest[0] = u[0] + v[0];
651
+ dest[1] = u[1] + v[1];
652
+ dest[2] = u[2] + v[2];
653
+ dest[3] = u[3] + v[3];
654
+ return dest;
655
+ }
656
+
657
+ function projectVec4(v) {
658
+ var f = 1.0 / v[3];
659
+ return [v[0] * f, v[1] * f, v[2] * f, 1.0];
660
+ }
661
+
662
+ function transformPoints3(m, points) {
663
+ var result = new Array(points.length);
664
+ var len = points.length;
665
+ var p0, p1, p2;
666
+ var pi;
667
+ // cache values
668
+ var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3];
669
+ var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7];
670
+ var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11];
671
+ var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15];
672
+ for (var i = 0; i < len; ++i) {
673
+ // cache values
674
+ pi = points[i];
675
+ p0 = pi[0];
676
+ p1 = pi[1];
677
+ p2 = pi[2];
678
+ result[i] = [
679
+ (m0 * p0) + (m4 * p1) + (m8 * p2) + m12,
680
+ (m1 * p0) + (m5 * p1) + (m9 * p2) + m13,
681
+ (m2 * p0) + (m6 * p1) + (m10 * p2) + m14,
682
+ (m3 * p0) + (m7 * p1) + (m11 * p2) + m15
683
+ ];
684
+ }
685
+ return result;
686
+ }
687
+
688
+ //function subVec2(u, v, dest) {
689
+ // if (!dest) {
690
+ // dest = u;
691
+ // }
692
+ // dest[0] = u[0] - v[0];
693
+ // dest[1] = u[1] - v[1];
694
+ // return dest;
695
+ //}
696
+ //
697
+ //function lenVec2(v) {
698
+ // return Math.sqrt(sqLenVec2(v));
699
+ //}
700
+
701
+ function sqLenVec2(v) {
702
+ return dotVector2(v, v);
703
+ }
704
+
705
+ function dotVector2(u, v) {
706
+ return (u[0] * v[0] + u[1] * v[1]);
707
+ }
708
+
709
+ var MAX_DOUBLE = Number.POSITIVE_INFINITY;
710
+ var MIN_DOUBLE = Number.NEGATIVE_INFINITY;
711
+
712
+ function Box3(min, max) {
713
+
714
+ this.min = min || [ MAX_DOUBLE, MAX_DOUBLE, MAX_DOUBLE ];
715
+ this.max = max || [ MIN_DOUBLE, MIN_DOUBLE, MIN_DOUBLE ];
716
+
717
+ this.init = function (min, max) {
718
+ this.min[0] = min[0];
719
+ this.min[1] = min[1];
720
+ this.min[2] = min[2];
721
+ this.max[0] = max[0];
722
+ this.max[1] = max[1];
723
+ this.max[2] = max[2];
724
+ return this;
725
+ };
726
+
727
+ this.fromPoints = function (points) {
728
+ var pointsLength = points.length;
729
+ for (var i = 0; i < pointsLength; ++i) {
730
+ // var points_i3 = points[i][3];
731
+ var points_i3 = 1;
732
+ var pDiv0 = points[i][0] / points_i3;
733
+ var pDiv1 = points[i][1] / points_i3;
734
+ var pDiv2 = points[i][2] / points_i3;
735
+
736
+ if (pDiv0 < this.min[0]) {
737
+ this.min[0] = pDiv0;
738
+ }
739
+ if (pDiv1 < this.min[1]) {
740
+ this.min[1] = pDiv1;
741
+ }
742
+ if (pDiv2 < this.min[2]) {
743
+ this.min[2] = pDiv2;
744
+ }
745
+ if (pDiv0 > this.max[0]) {
746
+ this.max[0] = pDiv0;
747
+ }
748
+ if (pDiv1 > this.max[1]) {
749
+ this.max[1] = pDiv1;
750
+ }
751
+ if (pDiv2 > this.max[2]) {
752
+ this.max[2] = pDiv2;
753
+ }
754
+ }
755
+ return this;
756
+ };
757
+
758
+ this.isEmpty = function () {
759
+ return (
760
+ (this.min[0] >= this.max[0]) &&
761
+ (this.min[1] >= this.max[1]) &&
762
+ (this.min[2] >= this.max[2])
763
+ );
764
+ };
765
+
766
+ this.getCenter = function () {
767
+ return [
768
+ (this.max[0] + this.min[0]) / 2.0,
769
+ (this.max[1] + this.min[1]) / 2.0,
770
+ (this.max[2] + this.min[2]) / 2.0
771
+ ];
772
+ };
773
+
774
+ this.getSize = function () {
775
+ return [
776
+ (this.max[0] - this.min[0]),
777
+ (this.max[1] - this.min[1]),
778
+ (this.max[2] - this.min[2])
779
+ ];
780
+ };
781
+
782
+ this.getFacesAreas = function () {
783
+ var s = this.size;
784
+ return [
785
+ (s[1] * s[2]),
786
+ (s[0] * s[2]),
787
+ (s[0] * s[1])
788
+ ];
789
+ };
790
+
791
+ this.getSurfaceArea = function () {
792
+ var a = this.getFacesAreas();
793
+ return ((a[0] + a[1] + a[2]) * 2.0);
794
+ };
795
+
796
+ this.getVolume = function () {
797
+ var s = this.size;
798
+ return (s[0] * s[1] * s[2]);
799
+ };
800
+
801
+ this.getOffset = function (half_delta) {
802
+ this.min[0] -= half_delta;
803
+ this.min[1] -= half_delta;
804
+ this.min[2] -= half_delta;
805
+ this.max[0] += half_delta;
806
+ this.max[1] += half_delta;
807
+ this.max[2] += half_delta;
808
+ return this;
809
+ };
810
+ }