jax 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  var Jax = {
2
2
  PRODUCTION: 1,
3
3
 
4
- VERSION: "1.1.0",
4
+ VERSION: "1.1.1.rc1",
5
5
 
6
6
  webgl_not_supported_path: "/webgl_not_supported.html",
7
7
 
@@ -44,7 +44,6 @@ if (typeof(document) == "undefined") {
44
44
  Jax.getGlobal().document = require("helpers/node_dom_emulator");
45
45
  }
46
46
 
47
-
48
47
  Jax.Compatibility = (function() {
49
48
  var offsetTop = 1;
50
49
  var offsetLeft = 1;
@@ -2070,6 +2069,62 @@ mat3.multiplyVec3 = function(matrix, vec, dest) {
2070
2069
  };
2071
2070
  mat4.IDENTITY = mat4.identity(mat4.create());
2072
2071
 
2072
+ quat4.fromAxes = function(view, right, up, dest) {
2073
+ var mat = quat4.fromAxes.mat = quat4.fromAxes.mat || mat3.create();
2074
+
2075
+ mat[0] = right[0];
2076
+ mat[3] = right[1];
2077
+ mat[6] = right[2];
2078
+
2079
+ mat[1] = up[0];
2080
+ mat[4] = up[1];
2081
+ mat[7] = up[2];
2082
+
2083
+ mat[2] = view[0];
2084
+ mat[5] = view[1];
2085
+ mat[8] = view[2];
2086
+
2087
+ quat4.fromRotationMatrix(mat, dest);
2088
+ };
2089
+
2090
+ quat4.fromRotationMatrix = function(mat, dest) {
2091
+ if (!dest) dest = quat4.create();
2092
+
2093
+
2094
+ var fTrace = mat[0] + mat[4] + mat[8];
2095
+ var fRoot;
2096
+
2097
+ if ( fTrace > 0.0 )
2098
+ {
2099
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
2100
+ dest[3] = 0.5 * fRoot;
2101
+ fRoot = 0.5/fRoot; // 1/(4w)
2102
+ dest[0] = (mat[7]-mat[5])*fRoot;
2103
+ dest[1] = (mat[2]-mat[6])*fRoot;
2104
+ dest[2] = (mat[3]-mat[1])*fRoot;
2105
+ }
2106
+ else
2107
+ {
2108
+ var s_iNext = quat4.fromRotationMatrix.s_iNext = quat4.fromRotationMatrix.s_iNext || [1,2,0];
2109
+ var i = 0;
2110
+ if ( mat[4] > mat[0] )
2111
+ i = 1;
2112
+ if ( mat[8] > mat[i*3+i] )
2113
+ i = 2;
2114
+ var j = s_iNext[i];
2115
+ var k = s_iNext[j];
2116
+
2117
+ fRoot = Math.sqrt(mat[i*3+i]-mat[j*3+j]-mat[k*3+k] + 1.0);
2118
+ dest[i] = 0.5 * fRoot;
2119
+ fRoot = 0.5 / fRoot;
2120
+ dest[3] = (mat[k*3+j] - mat[j*3+k]) * fRoot;
2121
+ dest[j] = (mat[j*3+i] + mat[i*3+j]) * fRoot;
2122
+ dest[k] = (mat[k*3+i] + mat[i*3+k]) * fRoot;
2123
+ }
2124
+
2125
+ return dest;
2126
+ };
2127
+
2073
2128
  quat4.toAngleAxis = function(src, dest) {
2074
2129
  if (!dest) dest = src;
2075
2130
 
@@ -3449,7 +3504,7 @@ Jax.Shader = (function() {
3449
3504
 
3450
3505
  getRawSource: function(options, which) {
3451
3506
  var source = this.options[which];
3452
- options = Jax.Util.normalizeOptions(options, {shader_type:which});
3507
+ options = Jax.Util.normalizeOptions(options, {shader:this,shader_type:which});
3453
3508
  if (source && (source = source.render(options))) {
3454
3509
  var result = this.getPreamble(options);
3455
3510
  if (!options || !options.skip_export_definitions)
@@ -3710,7 +3765,12 @@ Jax.Shader.Manifest = Jax.Class.create({
3710
3765
  texture: function(name, tex, context) {
3711
3766
  if (!context) throw new Error("Can't bind texture without a context");
3712
3767
  if (this.texture_tracker == GL_MAX_ACTIVE_TEXTURES-1) {
3713
- throw new Error("Maximum number of textures ("+GL_MAX_ACTIVE_TEXTURES+") has been reached!");
3768
+ /* FIXME add a callback for Materials to enter compatibility mode and recompile their shaders
3769
+ before throwing a hard error. Until this is implemented, the hard error itself is disabled
3770
+ because it causes unnecessary barfing on machines that are otherwise capable of running the
3771
+ scene. Using too many textures doesn't seem to have any catastrophic results on tested
3772
+ hardware, except some visual anomolies, so there's no reason to crash out catastrophically.
3773
+ */
3714
3774
  }
3715
3775
 
3716
3776
  if (typeof(this.getValue(name)) != "number")
@@ -3880,6 +3940,7 @@ Jax.ShaderChain = (function() {
3880
3940
 
3881
3941
  function preprocessorOptions(self) {
3882
3942
  return {
3943
+ shader: self,
3883
3944
  ignore_es_precision: true,
3884
3945
  export_prefix: self.getName(),
3885
3946
  exports: self.gatherExports(),
@@ -5350,7 +5411,7 @@ function calculateNormals(mesh) {
5350
5411
  for (var i in options)
5351
5412
  this[i] = options[i];
5352
5413
 
5353
- if (!this.draw_mode)
5414
+ if (this.draw_mode == undefined)
5354
5415
  this.draw_mode = GL_TRIANGLES;
5355
5416
  },
5356
5417
 
@@ -5398,7 +5459,7 @@ function calculateNormals(mesh) {
5398
5459
  var result = Jax.Util.normalizeOptions(options, {
5399
5460
  material: this.material,
5400
5461
  default_material: this.default_material,
5401
- draw_mode: this.draw_mode || GL_TRIANGLES
5462
+ draw_mode: this.draw_mode == undefined ? GL_TRIANGLES : this.draw_mode
5402
5463
  });
5403
5464
 
5404
5465
  if (!result.material) result.material = result.default_material;
@@ -5560,15 +5621,260 @@ Jax.Scene.ILLUMINATION_PASS = 1;
5560
5621
  Jax.Scene.AMBIENT_PASS = 2;
5561
5622
  Jax.Scene.SHADOWMAP_PASS = 3;
5562
5623
 
5563
- Jax.Geometry = {};
5624
+ Jax.Geometry = {
5625
+ DISJOINT: 0,
5626
+ COINCIDE: 1,
5627
+ INTERSECT: 2,
5628
+ };
5629
+
5630
+ Jax.Geometry.Line = (function() {
5631
+ var Line = Jax.Class.create({
5632
+ initialize: function(a, b) {
5633
+
5634
+ this.a = vec3.create();
5635
+
5636
+ this.b = vec3.create();
5637
+
5638
+ this.normal = vec3.create();
5639
+
5640
+ this.length = 0;
5641
+
5642
+ if (arguments.length) this.set(a, b);
5643
+ },
5644
+
5645
+ set: function(a, b) {
5646
+ vec3.set(a, this.a);
5647
+ vec3.set(b, this.b);
5648
+
5649
+ vec3.subtract(b, a, this.normal);
5650
+ this.length = vec3.length(this.normal);
5651
+ vec3.normalize(this.normal);
5652
+
5653
+ return this;
5654
+ },
5655
+
5656
+ intersectLineSegment: function(line, dest) {
5657
+ var u = vec3.subtract(this.b, this.a, vec3.create());
5658
+ var v = vec3.subtract(line.b, line.a, vec3.create());
5659
+ var w = vec3.subtract(this.a, line.a, vec3.create());
5660
+ var D = (u[0] * v[1] - u[1] * v[0]);
5661
+ if (Math.abs(D) < Math.EPSILON) { // S1 and S2 are parallel
5662
+ if ((u[0] * w[1] - u[1] * w[0]) != 0 || (v[0] * w[1] - v[1] * w[0]) != 0) {
5663
+ return Jax.Geometry.DISJOINT; // they are NOT colinear
5664
+ }
5665
+ var du = vec3.dot(u, u);
5666
+ var dv = vec3.dot(v, v);
5667
+ if (du == 0 && dv == 0) { // both segments are points
5668
+ if (!Math.equalish(this.a, line.a)) // they are distinct points
5669
+ return Jax.Geometry.DISJOINT;
5670
+ if (dest) vec3.set(line.a, dest.a);
5671
+ return Jax.Geometry.INTERSECT;
5672
+ }
5673
+ if (du == 0) { // +this+ is a single point
5674
+ if (!line.contains(this.a)) // but is not in S2
5675
+ return Jax.Geometry.DISJOINT;
5676
+ if (dest) vec3.set(this.a, dest.a);
5677
+ return Jax.Geometry.INTERSECT;
5678
+ }
5679
+ if (dv == 0) { // +line+ is a single point
5680
+ if (!this.contains(line.a)) // but is not in this line
5681
+ return Jax.Geometry.DISJOINT;
5682
+ if (dest) vec3.set(line.a, dest.a);
5683
+ return Jax.Geometry.INTERSECT;
5684
+ }
5685
+ var t0, t1; // endpoints of +this+ in eqn for +line+
5686
+ var w2 = vec3.subtract(this.a, line.a, vec3.create());
5687
+ if (v[0] != 0) {
5688
+ t0 = w[0] / v[0];
5689
+ t1 = w2[0] / v[0];
5690
+ } else {
5691
+ t0 = w[1] / v[1];
5692
+ t1 = w2[1] / v[1];
5693
+ }
5694
+ if (t0 > t1) { // must have t0 smaller than t1
5695
+ var t = t0; t0 = t1; t1 = t;
5696
+ }
5697
+ if (t0 > 1 || t1 < 0) // NO overlap
5698
+ return Jax.Geometry.DISJOINT;
5699
+ t0 = t0 < 0 ? 0 : t0; // clamp to min 0
5700
+ t1 = t1 > 1 ? 1 : t1; // clamp to max 1
5701
+ if (t0 == t1) {
5702
+ if (line) {
5703
+ vec3.add(line.a, vec3.scale(v, t0, dest.a), dest.a);
5704
+ return Jax.Geometry.INTERSECT;
5705
+ }
5706
+ }
5707
+
5708
+ if (dest) {
5709
+ vec3.add(line.a, vec3.scale(v, t0, dest.a), dest);
5710
+ vec3.add(line.b, vec3.scale(v, t1, dest.b), dest);
5711
+ }
5712
+ return Jax.Geometry.COINCIDENT;
5713
+ }
5714
+
5715
+ var sI = (v[0] * w[1] - v[1] * w[0]) / D;
5716
+ if (sI < 0 || sI > 1) // no intersect with +this+
5717
+ return Jax.Geometry.DISJOINT;
5718
+ var tI = (u[0] * w[1] - u[1] * w[0]) / D;
5719
+ if (tI < 0 || tI > 1) // no intersect with +line+
5720
+ return Jax.Geometry.DISJOINT;
5721
+
5722
+ if (dest) vec3.add(this.a, vec3.scale(u, sI, dest), dest);
5723
+ return Jax.Geometry.INTERSECT;
5724
+ },
5725
+
5726
+ toString: function() {
5727
+ return "[Line a:"+this.a+", b:"+this.b+"]";
5728
+ }
5729
+ });
5730
+
5731
+ Object.defineProperty(Line.prototype, 0, {
5732
+ get: function() { return this.a; },
5733
+ set: function(v) { return this.a = v; },
5734
+ enumerable: false,
5735
+ configurable: false
5736
+ });
5737
+
5738
+ Object.defineProperty(Line.prototype, 1, {
5739
+ get: function() { return this.b; },
5740
+ set: function(v) { return this.b = v; },
5741
+ enumerable: false,
5742
+ configurable: false
5743
+ });
5564
5744
 
5745
+ return Line;
5746
+ })();
5565
5747
  Jax.Geometry.Plane = (function() {
5748
+ var bufs = {};
5749
+
5566
5750
  function innerProduct(a, x, y, z) {
5567
5751
  return (a[0]*x + a[1]*y + a[2]*z);
5568
5752
  }
5569
5753
 
5570
- return Jax.Class.create({
5754
+ var Plane = Jax.Class.create({
5755
+ toString: function() {
5756
+ return "[Plane normal:"+this.normal+"; D:"+this.d+"]";
5757
+ },
5758
+
5759
+ intersectTriangle: function(t, line) {
5760
+ var ad = this.classify(t.a), bd = this.classify(t.b), cd = this.classify(t.c);
5761
+ var sideAB = ad * bd, sideBC = bd * cd;
5762
+ if (sideAB > 0.0 && sideBC > 0.0) return false; // all points on same side of plane
5763
+
5764
+ if (!line) return true;
5765
+
5766
+ var otherSide, sameSide1, sameSide2;
5767
+ if (sideAB > 0) {
5768
+ sameSide1 = t.a;
5769
+ sameSide2 = t.b;
5770
+ otherSide = t.c;
5771
+ } else {
5772
+ if (sideBC > 0) {
5773
+ otherSide = t.a;
5774
+ sameSide1 = t.b;
5775
+ sameSide2 = t.c;
5776
+ } else {
5777
+ sameSide1 = t.a;
5778
+ otherSide = t.b;
5779
+ sameSide2 = t.c;
5780
+ }
5781
+ }
5782
+
5783
+ var seg1 = bufs.tri_seg1 = bufs.tri_seg1 || new Jax.Geometry.Line();
5784
+ var seg2 = bufs.tri_seg2 = bufs.tri_seg2 || new Jax.Geometry.Line();
5785
+ seg1.set(otherSide, sameSide1);
5786
+ seg2.set(otherSide, sameSide2);
5787
+
5788
+ var p1 = bufs.tri_p1 = bufs.tri_p1 || vec3.create(),
5789
+ p2 = bufs.tri_p2 = bufs.tri_p2 || vec3.create();
5790
+ this.intersectLineSegment(seg1, p1);
5791
+ this.intersectLineSegment(seg2, p2);
5792
+ return line.set(p1, p2);
5793
+ },
5794
+
5795
+ intersectLineSegment: function(line, point) {
5796
+ var u = vec3.subtract(line.b, line.a, (bufs.lineseg_u = bufs.lineseg_u || vec3.create()));
5797
+ var w = vec3.subtract(line.a, this.point, (bufs.lineseg_w = bufs.lineseg_w || vec3.create()));
5798
+ var D = vec3.dot(this.normal, u);
5799
+ var N = -vec3.dot(this.normal, w);
5800
+
5801
+ if (Math.abs(D) < Math.EPSILON) // segment is parallel to plane
5802
+ if (N == 0) return Jax.Geometry.COINCIDE; // segment lies in plane
5803
+ else return Jax.Geometry.DISJOINT;
5804
+
5805
+ var sI = N / D;
5806
+ if (sI < 0 || sI > 1)
5807
+ return Jax.Geometry.DISJOINT;
5808
+
5809
+ if (point)
5810
+ vec3.add(line.a, vec3.scale(u, sI, point), point);
5811
+
5812
+ return Jax.Geometry.INTERSECT;
5813
+ },
5814
+
5815
+ intersectRay: function(origin, direction) {
5816
+ var numer = vec3.dot(this.normal, origin) + this.d;
5817
+ var denom = vec3.dot(this.normal, direction);
5818
+
5819
+ if (denom == 0) // normal is orthogonal to vector, can't intersect
5820
+ return false;
5821
+
5822
+ var result = -(numer / denom);
5823
+ return -(numer / denom);
5824
+ },
5825
+
5826
+ intersectPlane: function(p, line) {
5827
+ var d1 = this.d, d2 = p.d;
5828
+ var p1n = this.normal, p2n = p.normal;
5829
+ var u = bufs.u = bufs.u || vec3.create();
5830
+ vec3.cross(p1n, p2n, u);
5831
+ var ax = (u[0] >= 0 ? u[0] : -u[0]);
5832
+ var ay = (u[1] >= 0 ? u[1] : -u[1]);
5833
+ var az = (u[2] >= 0 ? u[2] : -u[2]);
5834
+
5835
+ if ((ax+ay+az) < Math.EPSILON) { // planes are near parallel
5836
+ if (Math.equalish(d1, d2)) return Jax.Geometry.COINCIDE;
5837
+ else return Jax.Geometry.DISJOINT;
5838
+ }
5839
+
5840
+ if (line) {
5841
+ var maxc;
5842
+ if (ax > ay)
5843
+ if (ax > az) maxc = 0;
5844
+ else maxc = 2;
5845
+ else
5846
+ if (ay > az) maxc = 1;
5847
+ else maxc = 2;
5848
+
5849
+ var iP = bufs.iP = bufs.iP || vec3.create(); // intersection point
5850
+ switch(maxc) {
5851
+ case 0: // intersect with x = 0
5852
+ iP[0] = 0;
5853
+ iP[1] = (d2 * p1n[2] - d1 * p2n[2]) / u[0];
5854
+ iP[2] = (d1 * p2n[1] - d2 * p1n[1]) / u[0];
5855
+ break;
5856
+ case 1: // intersect with y = 0
5857
+ iP[0] = (d1 * p2n[2] - d2 * p1n[2]) / u[1];
5858
+ iP[1] = 0;
5859
+ iP[2] = (d2 * p1n[0] - d1 * p2n[0]) / u[1];
5860
+ break;
5861
+ case 2: // intersect with z = 0
5862
+ iP[0] = (d2 * p1n[1] - d1 * p2n[1]) / u[2];
5863
+ iP[1] = (d1 * p2n[0] - d2 * p1n[0]) / u[2];
5864
+ iP[2] = 0;
5865
+ break;
5866
+ }
5867
+
5868
+ vec3.set(iP, line[0]);
5869
+ vec3.add(iP, u, line[1]);
5870
+ }
5871
+
5872
+ return Jax.Geometry.INTERSECT;
5873
+ },
5874
+
5571
5875
  initialize: function(points) {
5876
+ this.point = vec3.create();
5877
+
5572
5878
  this.normal = vec3.create([0,1,0]);
5573
5879
 
5574
5880
  this.d = 0.0;
@@ -5578,32 +5884,33 @@ Jax.Geometry.Plane = (function() {
5578
5884
  },
5579
5885
 
5580
5886
  classify: function(O) {
5581
- return vec3.dot(this.normal, O) + this.d;
5887
+ if (O.array) return vec3.dot(this.normal, O.array) + this.d;
5888
+ else return vec3.dot(this.normal, O) + this.d;
5582
5889
  },
5583
5890
 
5584
5891
  set: function() {
5585
- var points = arguments;
5586
- if (arguments.length != 3) points = arguments[0];
5587
- if (typeof(points[0]) == 'object' && points[0].array) {
5588
- var vec = vec3.create();
5589
- vec3.subtract(points[1].array, points[0].array, this.normal);
5590
- vec3.subtract(points[2].array, points[0].array, vec);
5591
- vec3.cross(this.normal, vec, this.normal);
5592
- vec3.normalize(this.normal);
5593
-
5594
- this.point = points[1].array;
5595
- this.d = -innerProduct(this.normal, this.point[0], this.point[1], this.point[2]);
5892
+ if (arguments.length == 2) {
5893
+ vec3.set(arguments[1], this.normal);
5894
+ this.d = -vec3.dot(arguments[1], arguments[0]);
5596
5895
  } else {
5597
- var vec = vec3.create();
5598
- vec3.subtract(points[1], points[0], this.normal);
5599
- vec3.subtract(points[2], points[0], vec);
5600
- vec3.cross(this.normal, vec, this.normal);
5601
- vec3.normalize(this.normal);
5602
-
5603
- this.point = points[1];
5604
- this.d = -innerProduct(this.normal, this.point[0], this.point[1], this.point[2]);
5896
+ var tmp1 = this.normal, tmp2 = vec3.create();
5897
+ var points = arguments;
5898
+
5899
+ if (arguments.length != 3) points = arguments[0];
5900
+ if (typeof(points[0]) == 'object' && points[0].array) {
5901
+ vec3.subtract(points[1].array, points[0].array, tmp1);
5902
+ vec3.subtract(points[2].array, points[0].array, tmp2);
5903
+ vec3.normalize(vec3.cross(tmp1, tmp2, this.normal));
5904
+ this.d = -vec3.dot(this.normal, points[0].array);
5905
+ } else {
5906
+ vec3.subtract(points[1], points[0], tmp1);
5907
+ vec3.subtract(points[2], points[0], tmp2);
5908
+ vec3.normalize(vec3.cross(tmp1, tmp2, this.normal));
5909
+ this.d = -vec3.dot(this.normal, points[0]);
5910
+ }
5605
5911
  }
5606
5912
 
5913
+ vec3.scale(this.normal, this.d, this.point);
5607
5914
  return this;
5608
5915
  },
5609
5916
 
@@ -5616,14 +5923,6 @@ Jax.Geometry.Plane = (function() {
5616
5923
  return this;
5617
5924
  },
5618
5925
 
5619
- distance: function(point)
5620
- {
5621
- var x, y, z;
5622
- if (arguments.length == 3) { x = arguments[0]; y = arguments[1]; z = arguments[2]; }
5623
- else if (point.array) { x = point.array[0]; y = point.array[1]; z = point.array[2]; }
5624
- else { x = point[0]; y = point[1]; z = point[2]; }
5625
- return this.d + innerProduct(this.normal, x, y, z);
5626
- },
5627
5926
 
5628
5927
  whereis: function()
5629
5928
  {
@@ -5638,68 +5937,244 @@ Jax.Geometry.Plane = (function() {
5638
5937
  return Jax.Geometry.Plane.INTERSECT;
5639
5938
  }
5640
5939
  });
5940
+
5941
+ Plane.prototype.distance = Plane.prototype.classify;
5942
+
5943
+ return Plane;
5641
5944
  })();
5642
5945
 
5643
5946
  Jax.Geometry.Plane.FRONT = 1;
5644
5947
  Jax.Geometry.Plane.BACK = 2;
5645
5948
  Jax.Geometry.Plane.INTERSECT = 3;
5646
5949
  Jax.Geometry.Triangle = (function() {
5647
- function SORT(isect) {
5648
- if(isect[0] > isect[1])
5950
+ /* for capturing point of intersection */
5951
+ var bufs;
5952
+ if (typeof(bufs) == 'undefined') // in case it was defined elsewhere
5953
+ bufs = {};
5954
+
5955
+
5956
+ function slow_tri_tri_intersect(t1, t2, dest)
5957
+ {
5958
+ var line1 = bufs.slowtri_line1 = bufs.slowtri_line1 || new Jax.Geometry.Line();
5959
+ var line2 = bufs.slowtri_line2 = bufs.slowtri_line2 || new Jax.Geometry.Line();
5960
+ if (t1.plane.intersectTriangle(t2, line1) && t2.plane.intersectTriangle(t1, line2)) {
5961
+ line1.intersectLineSegment(line2, dest);
5962
+ return true;
5963
+ }
5964
+ else return false;
5965
+
5966
+ /*
5967
+ var p1 = t1.plane;
5968
+ var f1, f2, f3, f12, f23;
5969
+ var other_side=0;
5970
+
5649
5971
  {
5650
- var c = isect[0];
5651
- isect[0] = isect[1];
5652
- isect[1] = c;
5972
+ f1=p1.classify(t2.a);
5973
+ f2=p1.classify(t2.b);
5974
+ f3=p1.classify(t2.c);
5975
+ f12=f1*f2;
5976
+ f23=f2*f3;
5977
+ if (f12>0.0 && f23>0.0)
5978
+ return false;
5979
+ other_side=(f12<0.0?(f23<0.0?1:0):2);
5653
5980
  }
5654
- }
5655
5981
 
5656
- function ISECT(VV0, VV1, VV2, D0, D1, D2, isect) {
5657
- isect[0] = VV0 + (VV1 - VV0) * D0 / (D0 - D1);
5658
- isect[1] = VV0 + (VV2 - VV0) * D0 / (D0 - D2);
5659
- }
5982
+ var p2 = t2.plane;
5983
+ var n12 = bufs.slowtritri_n12 = bufs.slowtritri_n12 || vec3.create();
5984
+ vec3.add(p1.normal, p2.normal, n12);
5985
+ var a2 = t2[(other_side+1) % 3];
5986
+ var b2 = t2[other_side];
5987
+ var c2 = t2[(other_side+2) % 3];
5988
+
5989
+ var t21 = -(p1.d + p2.d + vec3.dot(a2, n12)) / vec3.dot(vec3.subtract(b2, a2, dest), n12);
5990
+ vec3.add(a2, vec3.scale(dest, t21, dest), dest);
5991
+ if (t1.pointInTri(dest)) return dest;
5992
+
5993
+ var t22 = -(p1.d + p2.d + vec3.dot(c2, n12)) / vec3.dot(vec3.subtract(b2, c2, dest), n12);
5994
+ vec3.add(c2, vec3.scale(dest, t22, dest), dest);
5995
+ if (t1.pointInTri(dest)) return dest;
5660
5996
 
5661
- function COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect) {
5662
- if(D0D1 > 0)
5663
5997
  {
5664
- /* here we know that D0D2<=0.0 */
5665
- /* that is D0, D1 are on the same side, D2 on the other or on the plane */
5666
- ISECT(VV2,VV0,VV1,D2,D0,D1,isect);
5998
+ f1=p2.classify(t1.a);
5999
+ f2=p2.classify(t1.b);
6000
+ f3=p2.classify(t1.c);
6001
+ f12=f1*f2;
6002
+ f23=f2*f3;
6003
+ if (f12>0.0 && f23>0.0)
6004
+ return false;
6005
+ other_side=(f12<0.0?(f23<0.0?1:0):2);
5667
6006
  }
5668
- else if(D0D2 > 0)
6007
+
6008
+ var a1 = t1[(other_side+1)%3];
6009
+ var b1 = t1[other_side];
6010
+ var c1 = t1[(other_side+2)%3];
6011
+
6012
+ var t11 = -(p1.d + p2.d + vec3.dot(a1, n12)) / vec3.dot(vec3.subtract(b1, a1, dest), n12);
6013
+ vec3.add(a1, vec3.scale(dest, t11, dest), dest);
6014
+ if (t2.pointInTri(dest)) return dest;
6015
+
6016
+ var t12 = -(p1.d + p2.d + vec3.dot(c1, n12)) / vec3.dot(vec3.subtract(b1, c1, dest), n12);
6017
+ vec3.add(c1, vec3.scale(dest, t12, dest), dest);
6018
+ if (t2.pointInTri(dest)) return dest;
6019
+
6020
+ return false;
6021
+ */
6022
+ }
6023
+
6024
+ /* faster than capturing intersection point when we don't care about it */
6025
+ var bufs;
6026
+ if (typeof(bufs) != 'undefined') // in case it was defined elsewhere
6027
+ bufs = {};
6028
+
6029
+
6030
+
6031
+
6032
+
6033
+
6034
+
6035
+ /* sort so that a<=b */
6036
+
6037
+
6038
+
6039
+
6040
+
6041
+
6042
+
6043
+
6044
+ /* this edge to edge test is based on Franlin Antonio's gem:
6045
+ "Faster Line Segment Intersection", in Graphics Gems III,
6046
+ pp. 199-202 */
6047
+
6048
+
6049
+
6050
+
6051
+
6052
+
6053
+ function coplanar_tri_tri(N, V0, V1, V2, U0, U1, U2) {
6054
+ var A = bufs.tritri_A = bufs.tritri_A || vec3.create();
6055
+ var i0, i1;
6056
+
6057
+ /* first project onto an axis-aligned plane, that maximizes the area */
6058
+ /* of the triangles, compute indices: i0,i1. */
6059
+ A[0] = Math.abs(N[0]);
6060
+ A[1] = Math.abs(N[1]);
6061
+ A[2] = Math.abs(N[2]);
6062
+
6063
+ if(A[0]>A[1])
5669
6064
  {
5670
- /* here we know that d0d1<=0.0 */
5671
- ISECT(VV1,VV0,VV2,D1,D0,D2,isect);
6065
+ if(A[0]>A[2])
6066
+ {
6067
+ i0=1; /* A[0] is greatest */
6068
+ i1=2;
6069
+ }
6070
+ else
6071
+ {
6072
+ i0=0; /* A[2] is greatest */
6073
+ i1=1;
6074
+ }
5672
6075
  }
5673
- else if(D1 * D2 > 0 || D0 != 0)
6076
+ else /* A[0]<=A[1] */
5674
6077
  {
5675
- /* here we know that d0d1<=0.0 or that D0!=0.0 */
5676
- ISECT(VV0,VV1,VV2,D0,D1,D2,isect);
6078
+ if(A[2]>A[1])
6079
+ {
6080
+ i0=0; /* A[2] is greatest */
6081
+ i1=1;
6082
+ }
6083
+ else
6084
+ {
6085
+ i0=0; /* A[1] is greatest */
6086
+ i1=2;
6087
+ }
5677
6088
  }
5678
- else if(D1 != 0)
6089
+
6090
+ /* test all edges of triangle 1 against the edges of triangle 2 */
6091
+ /* (inline function EDGE_AGAINST_TRI_EDGES) */
6092
+
6093
+ {
6094
+ var Ax,Ay,Bx,By,Cx,Cy,e,d,f;
6095
+ Ax=V1[i0]-V0[i0];
6096
+ Ay=V1[i1]-V0[i1];
6097
+ /* test edge U0,U1 against V0,V1 */
6098
+ /* (inline function EDGE_EDGE_TEST) */
6099
+
6100
+ Bx=U0[i0]-U1[i0];
6101
+ By=U0[i1]-U1[i1];
6102
+ Cx=V0[i0]-U0[i0];
6103
+ Cy=V0[i1]-U0[i1];
6104
+ f=Ay*Bx-Ax*By;
6105
+ d=By*Cx-Bx*Cy;
6106
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
5679
6107
  {
5680
- ISECT(VV1,VV0,VV2,D1,D0,D2,isect);
6108
+ e=Ax*Cy-Ay*Cx;
6109
+ if(f>0)
6110
+ {
6111
+ if(e>=0 && e<=f) return true;
6112
+ }
6113
+ else
6114
+ {
6115
+ if(e<=0 && e>=f) return true;
6116
+ }
5681
6117
  }
5682
- else if(D2 != 0)
6118
+
6119
+ /* test edge U1,U2 against V0,V1 */
6120
+ /* (inline function EDGE_EDGE_TEST) */
6121
+
6122
+ Bx=U1[i0]-U2[i0];
6123
+ By=U1[i1]-U2[i1];
6124
+ Cx=V0[i0]-U1[i0];
6125
+ Cy=V0[i1]-U1[i1];
6126
+ f=Ay*Bx-Ax*By;
6127
+ d=By*Cx-Bx*Cy;
6128
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
5683
6129
  {
5684
- ISECT(VV2,VV0,VV1,D2,D0,D1,isect);
6130
+ e=Ax*Cy-Ay*Cx;
6131
+ if(f>0)
6132
+ {
6133
+ if(e>=0 && e<=f) return true;
6134
+ }
6135
+ else
6136
+ {
6137
+ if(e<=0 && e>=f) return true;
6138
+ }
5685
6139
  }
5686
- else
6140
+
6141
+ /* test edge U2,U1 against V0,V1 */
6142
+ /* (inline function EDGE_EDGE_TEST) */
6143
+
6144
+ Bx=U2[i0]-U0[i0];
6145
+ By=U2[i1]-U0[i1];
6146
+ Cx=V0[i0]-U2[i0];
6147
+ Cy=V0[i1]-U2[i1];
6148
+ f=Ay*Bx-Ax*By;
6149
+ d=By*Cx-Bx*Cy;
6150
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
5687
6151
  {
5688
- /* triangles are coplanar */
5689
- throw 1;
6152
+ e=Ax*Cy-Ay*Cx;
6153
+ if(f>0)
6154
+ {
6155
+ if(e>=0 && e<=f) return true;
6156
+ }
6157
+ else
6158
+ {
6159
+ if(e<=0 && e>=f) return true;
6160
+ }
5690
6161
  }
5691
- }
5692
6162
 
5693
- /* this edge to edge test is based on Franlin Antonio's gem:
5694
- "Faster Line Segment Intersection", in Graphics Gems III,
5695
- pp. 199-202 */
5696
- function EDGE_EDGE_TEST(Ax, Ay, V0,U0,U1, i0, i1) {
5697
- var Bx,By,Cx,Cy,e,d,f;
6163
+ }
6164
+
6165
+ /* (inline function EDGE_AGAINST_TRI_EDGES) */
6166
+
6167
+ {
6168
+ var Ax,Ay,Bx,By,Cx,Cy,e,d,f;
6169
+ Ax=V2[i0]-V1[i0];
6170
+ Ay=V2[i1]-V1[i1];
6171
+ /* test edge U0,U1 against V1,V2 */
6172
+ /* (inline function EDGE_EDGE_TEST) */
5698
6173
 
5699
6174
  Bx=U0[i0]-U1[i0];
5700
6175
  By=U0[i1]-U1[i1];
5701
- Cx=V0[i0]-U0[i0];
5702
- Cy=V0[i1]-U0[i1];
6176
+ Cx=V1[i0]-U0[i0];
6177
+ Cy=V1[i1]-U0[i1];
5703
6178
  f=Ay*Bx-Ax*By;
5704
6179
  d=By*Cx-Bx*Cy;
5705
6180
  if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
@@ -5714,108 +6189,190 @@ function EDGE_EDGE_TEST(Ax, Ay, V0,U0,U1, i0, i1) {
5714
6189
  if(e<=0 && e>=f) return true;
5715
6190
  }
5716
6191
  }
5717
- return false;
5718
- }
5719
6192
 
5720
- function EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2, i0, i1)
5721
- {
5722
- var Ax,Ay;
5723
- Ax=V1[i0]-V0[i0];
5724
- Ay=V1[i1]-V0[i1];
5725
-
5726
- /* test edge U0,U1 against V0,V1 */
5727
- return EDGE_EDGE_TEST(Ax,Ay, V0,U0,U1, i0,i1) ||
5728
- /* test edge U1,U2 against V0,V1 */
5729
- EDGE_EDGE_TEST(Ax,Ay, V0,U1,U2, i0,i1) ||
5730
- /* test edge U2,U1 against V0,V1 */
5731
- EDGE_EDGE_TEST(Ax,Ay, V0,U2,U0, i0,i1);
5732
- }
6193
+ /* test edge U1,U2 against V1,V2 */
6194
+ /* (inline function EDGE_EDGE_TEST) */
5733
6195
 
5734
- function POINT_IN_TRI(V0,U0,U1,U2, i0,i1)
5735
- {
5736
- var a,b,c,d0,d1,d2;
5737
- /* is T1 completly inside T2? */
5738
- /* check if V0 is inside tri(U0,U1,U2) */
5739
- a = U1[i1]-U0[i1];
5740
- b = -(U1[i0]-U0[i0]);
5741
- c = -a*U0[i0]-b*U0[i1];
5742
- d0 = a*V0[i0]+b*V0[i1]+c;
5743
-
5744
- a = U2[i1]-U1[i1];
5745
- b = -(U2[i0]-U1[i0]);
5746
- c = -a*U1[i0]-b*U1[i1];
5747
- d1 = a*V0[i0]+b*V0[i1]+c;
5748
-
5749
- a = U0[i1] - U2[i1];
5750
- b = - (U0[i0] - U2[i0]);
5751
- c = -a * U2[i0] - b * U2[i1];
5752
- d2 = a * V0[i0] + b * V0[i1] + c;
5753
-
5754
- if(d0 * d1 > 0.0)
6196
+ Bx=U1[i0]-U2[i0];
6197
+ By=U1[i1]-U2[i1];
6198
+ Cx=V1[i0]-U1[i0];
6199
+ Cy=V1[i1]-U1[i1];
6200
+ f=Ay*Bx-Ax*By;
6201
+ d=By*Cx-Bx*Cy;
6202
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
5755
6203
  {
5756
- if(d0 * d2 > 0.0) return true;
6204
+ e=Ax*Cy-Ay*Cx;
6205
+ if(f>0)
6206
+ {
6207
+ if(e>=0 && e<=f) return true;
6208
+ }
6209
+ else
6210
+ {
6211
+ if(e<=0 && e>=f) return true;
6212
+ }
5757
6213
  }
5758
- return false;
5759
- }
5760
6214
 
5761
- function coplanar_tri_tri(N, V0, V1, V2, U0, U1, U2) {
5762
- var A = this.A = this.A || vec3.create();
5763
- var i0, i1;
6215
+ /* test edge U2,U1 against V1,V2 */
6216
+ /* (inline function EDGE_EDGE_TEST) */
5764
6217
 
5765
- /* first project onto an axis-aligned plane, that maximizes the area */
5766
- /* of the triangles, compute indices: i0,i1. */
5767
- A[0] = Math.abs(N[0]);
5768
- A[1] = Math.abs(N[1]);
5769
- A[2] = Math.abs(N[2]);
6218
+ Bx=U2[i0]-U0[i0];
6219
+ By=U2[i1]-U0[i1];
6220
+ Cx=V1[i0]-U2[i0];
6221
+ Cy=V1[i1]-U2[i1];
6222
+ f=Ay*Bx-Ax*By;
6223
+ d=By*Cx-Bx*Cy;
6224
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
6225
+ {
6226
+ e=Ax*Cy-Ay*Cx;
6227
+ if(f>0)
6228
+ {
6229
+ if(e>=0 && e<=f) return true;
6230
+ }
6231
+ else
6232
+ {
6233
+ if(e<=0 && e>=f) return true;
6234
+ }
6235
+ }
6236
+
6237
+ }
6238
+
6239
+ /* (inline function EDGE_AGAINST_TRI_EDGES) */
5770
6240
 
5771
- if(A[0]>A[1])
5772
6241
  {
5773
- if(A[0]>A[2])
6242
+ var Ax,Ay,Bx,By,Cx,Cy,e,d,f;
6243
+ Ax=V0[i0]-V2[i0];
6244
+ Ay=V0[i1]-V2[i1];
6245
+ /* test edge U0,U1 against V2,V0 */
6246
+ /* (inline function EDGE_EDGE_TEST) */
6247
+
6248
+ Bx=U0[i0]-U1[i0];
6249
+ By=U0[i1]-U1[i1];
6250
+ Cx=V2[i0]-U0[i0];
6251
+ Cy=V2[i1]-U0[i1];
6252
+ f=Ay*Bx-Ax*By;
6253
+ d=By*Cx-Bx*Cy;
6254
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
6255
+ {
6256
+ e=Ax*Cy-Ay*Cx;
6257
+ if(f>0)
5774
6258
  {
5775
- i0=1; /* A[0] is greatest */
5776
- i1=2;
6259
+ if(e>=0 && e<=f) return true;
5777
6260
  }
5778
6261
  else
5779
6262
  {
5780
- i0=0; /* A[2] is greatest */
5781
- i1=1;
6263
+ if(e<=0 && e>=f) return true;
5782
6264
  }
5783
6265
  }
5784
- else /* A[0]<=A[1] */
6266
+
6267
+ /* test edge U1,U2 against V2,V0 */
6268
+ /* (inline function EDGE_EDGE_TEST) */
6269
+
6270
+ Bx=U1[i0]-U2[i0];
6271
+ By=U1[i1]-U2[i1];
6272
+ Cx=V2[i0]-U1[i0];
6273
+ Cy=V2[i1]-U1[i1];
6274
+ f=Ay*Bx-Ax*By;
6275
+ d=By*Cx-Bx*Cy;
6276
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
5785
6277
  {
5786
- if(A[2]>A[1])
6278
+ e=Ax*Cy-Ay*Cx;
6279
+ if(f>0)
5787
6280
  {
5788
- i0=0; /* A[2] is greatest */
5789
- i1=1;
6281
+ if(e>=0 && e<=f) return true;
5790
6282
  }
5791
6283
  else
5792
6284
  {
5793
- i0=0; /* A[1] is greatest */
5794
- i1=2;
6285
+ if(e<=0 && e>=f) return true;
5795
6286
  }
5796
6287
  }
5797
6288
 
5798
- /* test all edges of triangle 1 against the edges of triangle 2 */
5799
- if (EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2,i0,i1) ||
5800
- EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2,i0,i1) ||
5801
- EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2,i0,i1)) return true;
6289
+ /* test edge U2,U1 against V2,V0 */
6290
+ /* (inline function EDGE_EDGE_TEST) */
6291
+
6292
+ Bx=U2[i0]-U0[i0];
6293
+ By=U2[i1]-U0[i1];
6294
+ Cx=V2[i0]-U2[i0];
6295
+ Cy=V2[i1]-U2[i1];
6296
+ f=Ay*Bx-Ax*By;
6297
+ d=By*Cx-Bx*Cy;
6298
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f))
6299
+ {
6300
+ e=Ax*Cy-Ay*Cx;
6301
+ if(f>0)
6302
+ {
6303
+ if(e>=0 && e<=f) return true;
6304
+ }
6305
+ else
6306
+ {
6307
+ if(e<=0 && e>=f) return true;
6308
+ }
6309
+ }
6310
+
6311
+ }
6312
+
5802
6313
 
5803
6314
  /* finally, test if tri1 is totally contained in tri2 or vice versa */
5804
- if (POINT_IN_TRI(V0,U0,U1,U2, i0,i1) ||
5805
- POINT_IN_TRI(U0,V0,V1,V2, i0,i1)) return true;
6315
+ /* (inline function POINT_IN_TRI) */
6316
+
6317
+ {
6318
+ var a,b,c,d0,d1,d2;
6319
+ /* is T1 completly inside T2? */
6320
+ /* check if V0 is inside tri(U0,U1,U2) */
6321
+ a=U1[i1]-U0[i1];
6322
+ b=-(U1[i0]-U0[i0]);
6323
+ c=-a*U0[i0]-b*U0[i1];
6324
+ d0=a*V0[i0]+b*V0[i1]+c;
6325
+ a=U2[i1]-U1[i1];
6326
+ b=-(U2[i0]-U1[i0]);
6327
+ c=-a*U1[i0]-b*U1[i1];
6328
+ d1=a*V0[i0]+b*V0[i1]+c;
6329
+ a=U0[i1]-U2[i1];
6330
+ b=-(U0[i0]-U2[i0]);
6331
+ c=-a*U2[i0]-b*U2[i1];
6332
+ d2=a*V0[i0]+b*V0[i1]+c;
6333
+ if(d0*d1>0.0)
6334
+ {
6335
+ if(d0*d2>0.0) return true;
6336
+ }
6337
+ }
6338
+
6339
+ /* (inline function POINT_IN_TRI) */
6340
+
6341
+ {
6342
+ var a,b,c,d0,d1,d2;
6343
+ /* is T1 completly inside T2? */
6344
+ /* check if U0 is inside tri(V0,V1,V2) */
6345
+ a=V1[i1]-V0[i1];
6346
+ b=-(V1[i0]-V0[i0]);
6347
+ c=-a*V0[i0]-b*V0[i1];
6348
+ d0=a*U0[i0]+b*U0[i1]+c;
6349
+ a=V2[i1]-V1[i1];
6350
+ b=-(V2[i0]-V1[i0]);
6351
+ c=-a*V1[i0]-b*V1[i1];
6352
+ d1=a*U0[i0]+b*U0[i1]+c;
6353
+ a=V0[i1]-V2[i1];
6354
+ b=-(V0[i0]-V2[i0]);
6355
+ c=-a*V2[i0]-b*V2[i1];
6356
+ d2=a*U0[i0]+b*U0[i1]+c;
6357
+ if(d0*d1>0.0)
6358
+ {
6359
+ if(d0*d2>0.0) return true;
6360
+ }
6361
+ }
6362
+
5806
6363
 
5807
6364
  return false;
5808
6365
  }
5809
6366
 
5810
6367
  function tri_tri_intersect(V0, V1, V2, U0, U1, U2)
5811
6368
  {
5812
- var E1 = this.E1 = this.E1 || vec3.create(),
5813
- E2 = this.E2 = this.E2 || vec3.create(),
5814
- N1 = this.N1 = this.N1 || vec3.create(),
5815
- N2 = this.N2 = this.N2 || vec3.create(),
5816
- D = this.D = this.D || vec3.create(),
5817
- isect1 = this.isect1 = this.isect1 || vec2.create(),
5818
- isect2 = this.isect2 = this.isect2 || vec2.create();
6369
+ var E1 = bufs.tritri_E1 = bufs.tritri_E1 || vec3.create(),
6370
+ E2 = bufs.tritri_E2 = bufs.tritri_E2 || vec3.create(),
6371
+ N1 = bufs.tritri_N1 = bufs.tritri_N1 || vec3.create(),
6372
+ N2 = bufs.tritri_N2 = bufs.tritri_N2 || vec3.create(),
6373
+ D = bufs.tritri_D = bufs.tritri_D || vec3.create(),
6374
+ isect1 = bufs.tritri_isect1 = bufs.tritri_isect1 || vec2.create(),
6375
+ isect2 = bufs.tritri_isect2 = bufs.tritri_isect2 || vec2.create();
5819
6376
  var d1, d2;
5820
6377
  var du0,du1,du2,dv0,dv1,dv2;
5821
6378
  var du0du1,du0du2,dv0dv1,dv0dv2;
@@ -5892,17 +6449,137 @@ function tri_tri_intersect(V0, V1, V2, U0, U1, U2)
5892
6449
 
5893
6450
  try {
5894
6451
  /* compute interval for triangle 1 */
5895
- COMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,isect1);
6452
+ /* (inline function COMPUTE_INTERVALS) */
6453
+
6454
+ if(dv0dv1>0.0)
6455
+ {
6456
+ /* here we know that dv0dv2<=0.0 */
6457
+ /* that is dv0, dv1 are on the same side, dv2 on the other or on the plane */
6458
+ /* (inline function ISECT) */
6459
+
6460
+ isect1[0]=vp2+(vp0-vp2)*dv2/(dv2-dv0);
6461
+ isect1[1]=vp2+(vp1-vp2)*dv2/(dv2-dv1);
6462
+
6463
+ }
6464
+ else if(dv0dv2>0.0)
6465
+ {
6466
+ /* here we know that d0d1<=0.0 */
6467
+ /* (inline function ISECT) */
6468
+
6469
+ isect1[0]=vp1+(vp0-vp1)*dv1/(dv1-dv0);
6470
+ isect1[1]=vp1+(vp2-vp1)*dv1/(dv1-dv2);
6471
+
6472
+ }
6473
+ else if(dv1*dv2>0.0 || dv0!=0.0)
6474
+ {
6475
+ /* here we know that d0d1<=0.0 or that dv0!=0.0 */
6476
+ /* (inline function ISECT) */
6477
+
6478
+ isect1[0]=vp0+(vp1-vp0)*dv0/(dv0-dv1);
6479
+ isect1[1]=vp0+(vp2-vp0)*dv0/(dv0-dv2);
6480
+
6481
+ }
6482
+ else if(dv1!=0.0)
6483
+ {
6484
+ /* (inline function ISECT) */
6485
+
6486
+ isect1[0]=vp1+(vp0-vp1)*dv1/(dv1-dv0);
6487
+ isect1[1]=vp1+(vp2-vp1)*dv1/(dv1-dv2);
6488
+
6489
+ }
6490
+ else if(dv2!=0.0)
6491
+ {
6492
+ /* (inline function ISECT) */
6493
+
6494
+ isect1[0]=vp2+(vp0-vp2)*dv2/(dv2-dv0);
6495
+ isect1[1]=vp2+(vp1-vp2)*dv2/(dv2-dv1);
6496
+
6497
+ }
6498
+ else
6499
+ {
6500
+ /* triangles are coplanar */
6501
+ return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);
6502
+ }
6503
+
5896
6504
 
5897
6505
  /* compute interval for triangle 2 */
5898
- COMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,isect2);
6506
+ /* (inline function COMPUTE_INTERVALS) */
6507
+
6508
+ if(du0du1>0.0)
6509
+ {
6510
+ /* here we know that du0du2<=0.0 */
6511
+ /* that is du0, du1 are on the same side, du2 on the other or on the plane */
6512
+ /* (inline function ISECT) */
6513
+
6514
+ isect2[0]=up2+(up0-up2)*du2/(du2-du0);
6515
+ isect2[1]=up2+(up1-up2)*du2/(du2-du1);
6516
+
6517
+ }
6518
+ else if(du0du2>0.0)
6519
+ {
6520
+ /* here we know that d0d1<=0.0 */
6521
+ /* (inline function ISECT) */
6522
+
6523
+ isect2[0]=up1+(up0-up1)*du1/(du1-du0);
6524
+ isect2[1]=up1+(up2-up1)*du1/(du1-du2);
6525
+
6526
+ }
6527
+ else if(du1*du2>0.0 || du0!=0.0)
6528
+ {
6529
+ /* here we know that d0d1<=0.0 or that du0!=0.0 */
6530
+ /* (inline function ISECT) */
6531
+
6532
+ isect2[0]=up0+(up1-up0)*du0/(du0-du1);
6533
+ isect2[1]=up0+(up2-up0)*du0/(du0-du2);
6534
+
6535
+ }
6536
+ else if(du1!=0.0)
6537
+ {
6538
+ /* (inline function ISECT) */
6539
+
6540
+ isect2[0]=up1+(up0-up1)*du1/(du1-du0);
6541
+ isect2[1]=up1+(up2-up1)*du1/(du1-du2);
6542
+
6543
+ }
6544
+ else if(du2!=0.0)
6545
+ {
6546
+ /* (inline function ISECT) */
6547
+
6548
+ isect2[0]=up2+(up0-up2)*du2/(du2-du0);
6549
+ isect2[1]=up2+(up1-up2)*du2/(du2-du1);
6550
+
6551
+ }
6552
+ else
6553
+ {
6554
+ /* triangles are coplanar */
6555
+ return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2);
6556
+ }
6557
+
5899
6558
  } catch(e) {
5900
6559
  if (e == 1) return coplanar_tri_tri(N1, V0, V1, V2, U0, U1, U2);
5901
6560
  throw e;
5902
6561
  }
5903
6562
 
5904
- SORT(isect1);
5905
- SORT(isect2);
6563
+ /* (inline function SORT) */
6564
+
6565
+ if(isect1[0]> isect1[1])
6566
+ {
6567
+ var c;
6568
+ c=isect1[0];
6569
+ isect1[0]= isect1[1];
6570
+ isect1[1]=c;
6571
+ }
6572
+
6573
+ /* (inline function SORT) */
6574
+
6575
+ if(isect2[0]> isect1[1])
6576
+ {
6577
+ var c;
6578
+ c=isect2[0];
6579
+ isect2[0]= isect1[1];
6580
+ isect1[1]=c;
6581
+ }
6582
+
5906
6583
 
5907
6584
  if(isect1[1] < isect2[0] || isect2[1] < isect1[0]) return false;
5908
6585
  return true;
@@ -5910,7 +6587,7 @@ function tri_tri_intersect(V0, V1, V2, U0, U1, U2)
5910
6587
 
5911
6588
  var bufs = {};
5912
6589
 
5913
- return Jax.Class.create({
6590
+ var Triangle = Jax.Class.create({
5914
6591
  initialize: function(a, b, c) {
5915
6592
  this.a = vec3.create();
5916
6593
  this.b = vec3.create();
@@ -6013,12 +6690,13 @@ function tri_tri_intersect(V0, V1, V2, U0, U1, U2)
6013
6690
  return false;
6014
6691
  },
6015
6692
 
6016
- intersectTriangle: function(t) {
6017
- return tri_tri_intersect(this.a, this.b, this.c, t.a, t.b, t.c);
6693
+ intersectTriangle: function(t, dest) {
6694
+ if (dest) return slow_tri_tri_intersect(this, t, dest);
6695
+ else return tri_tri_intersect(this.a, this.b, this.c, t.a, t.b, t.c);
6018
6696
  },
6019
6697
 
6020
6698
  updateDescription: function() {
6021
- var p = this._p = this._p || new Jax.Geometry.Plane(this.a, this.b, this.c);
6699
+ var p = this.plane = this.plane || new Jax.Geometry.Plane(this.a, this.b, this.c);
6022
6700
  var n = p.normal;
6023
6701
  var a = [Math.abs(n.x), Math.abs(n.y), Math.abs(n.z)];
6024
6702
 
@@ -6059,6 +6737,29 @@ function tri_tri_intersect(V0, V1, V2, U0, U1, U2)
6059
6737
  return a >= 0 && (a+b) <= 1;
6060
6738
  }
6061
6739
  });
6740
+
6741
+ Object.defineProperty(Triangle.prototype, 0, {
6742
+ get: function() { return this.a; },
6743
+ set: function(v) { return this.a = v; },
6744
+ enumerable: false,
6745
+ configurable: false
6746
+ });
6747
+
6748
+ Object.defineProperty(Triangle.prototype, 1, {
6749
+ get: function() { return this.b; },
6750
+ set: function(v) { return this.b = v; },
6751
+ enumerable: false,
6752
+ configurable: false
6753
+ });
6754
+
6755
+ Object.defineProperty(Triangle.prototype, 2, {
6756
+ get: function() { return this.c; },
6757
+ set: function(v) { return this.c = v; },
6758
+ enumerable: false,
6759
+ configurable: false
6760
+ });
6761
+
6762
+ return Triangle;
6062
6763
  })();
6063
6764
 
6064
6765
  Jax.Scene.Frustum = (function() {
@@ -6700,12 +7401,15 @@ Jax.Scene.LightManager = (function() {
6700
7401
  options = Jax.Util.normalizeOptions(options, {});
6701
7402
 
6702
7403
  context.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6703
- for (var i = 0; i < this._lights.length; i++) {
7404
+ var i;
7405
+ for (i = 0; i < this._lights.length; i++) {
7406
+ if (i == 1) context.glBlendFunc(GL_ONE, GL_ONE);
6704
7407
  this._current_light = i;
6705
7408
  this._lights[i].render(context, this.objects, options);
6706
- if (i == 0) context.glBlendFunc(GL_ONE, GL_ONE);
6707
7409
  }
6708
7410
 
7411
+ if (i > 0) context.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
7412
+
6709
7413
  delete this._current_light;
6710
7414
  },
6711
7415
 
@@ -6886,12 +7590,19 @@ Jax.Camera = (function() {
6886
7590
  var vec;
6887
7591
  if (arguments.length == 3) vec = arguments;
6888
7592
  else vec = vec3.create(vector);
7593
+ vec3.scale(vec, -1);
6889
7594
  vec3.normalize(vec);
6890
7595
 
6891
- var rotquat = vec3.toQuatRotation(storeVecBuf(this, VIEW), vec, tmpRotQuat(this));
6892
- quat4.multiply(rotquat, this.rotation, this.rotation);
6893
- quat4.normalize(this.rotation);
7596
+ if (this.fixed_yaw) {
7597
+ var right = vec3.normalize(vec3.cross(this.fixed_yaw_axis, vec, vec3.create()));
7598
+ var up = vec3.normalize(vec3.cross(vec, right, vec3.create()));
7599
+ quat4.fromAxes(vec, right, up, this.rotation);
7600
+ } else {
7601
+ var rotquat = vec3.toQuatRotation(storeVecBuf(this, VIEW), vec, tmpRotQuat(this));
7602
+ quat4.multiply(rotquat, this.rotation, this.rotation);
7603
+ }
6894
7604
 
7605
+ quat4.normalize(this.rotation);
6895
7606
  this.fireEvent('updated');
6896
7607
  return this;
6897
7608
  },
@@ -7079,7 +7790,25 @@ Jax.Camera = (function() {
7079
7790
  return this;
7080
7791
  },
7081
7792
 
7082
- reset: function() { this.lookAt([0,0,-1], [0,0,0]); }
7793
+ projectMovement: function(forward, strafe, dest) {
7794
+ if (!strafe) strafe = 0;
7795
+ if (!dest) dest = vec3.create();
7796
+
7797
+ var view = vec3.scale(storeVecBuf(this, VIEW), forward);
7798
+ var right = vec3.scale(storeVecBuf(this, RIGHT), strafe);
7799
+ vec3.set(this.position, dest);
7800
+ vec3.add(view, dest, dest);
7801
+ vec3.add(right, dest, dest);
7802
+
7803
+ return dest;
7804
+ },
7805
+
7806
+ reset: function() {
7807
+ this.position[0] = this.position[1] = this.position[2] = 0;
7808
+ this.rotation[0] = this.rotation[1] = this.rotation[2] = 0;
7809
+ this.rotation[3] = 1;
7810
+ this.fireEvent('updated');
7811
+ }
7083
7812
  });
7084
7813
  })();
7085
7814
 
@@ -7193,22 +7922,23 @@ Jax.World = (function() {
7193
7922
 
7194
7923
  /* this.current_pass is used by the material */
7195
7924
 
7196
- this.context.current_pass = Jax.Scene.AMBIENT_PASS;
7197
7925
  this.context.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
7198
7926
  var unlit = Jax.Util.normalizeOptions(options, {unlit:true});
7199
7927
 
7200
- if (this.lighting.isEnabled() && (!unlit.material || unlit.material.supportsLighting())) {
7928
+ if (this.lighting.isEnabled() && (!unlit.material || (unlit.material.supportsLighting && unlit.material.supportsLighting()))) {
7929
+ /* illumination pass */
7930
+ this.context.current_pass = Jax.Scene.ILLUMINATION_PASS;
7931
+ this.lighting.illuminate(this.context, options);
7932
+
7201
7933
  /* ambient pass - unlit objects only because lit objects get ambient+diffuse+specular in one pass */
7934
+ this.context.current_pass = Jax.Scene.AMBIENT_PASS;
7202
7935
  for (i = 0; i < this.objects.length; i++)
7203
7936
  if (!this.objects[i].isLit()) {
7204
7937
  unlit.model_index = i;
7205
7938
  this.objects[i].render(this.context, unlit);
7206
7939
  }
7207
-
7208
- /* illumination pass */
7209
- this.context.current_pass = Jax.Scene.ILLUMINATION_PASS;
7210
- this.lighting.illuminate(this.context, options);
7211
7940
  } else {
7941
+ this.context.current_pass = Jax.Scene.AMBIENT_PASS;
7212
7942
  for (i = 0; i < this.objects.length; i++) {
7213
7943
  unlit.model_index = i;
7214
7944
  this.objects[i].render(this.context, unlit);
@@ -7618,6 +8348,12 @@ Jax.EVENT_METHODS = (function() {
7618
8348
  var cumulativeOffset = getCumulativeOffset(self.canvas);
7619
8349
  mouse.x = evt.pageX - cumulativeOffset[0];
7620
8350
  mouse.y = evt.pageY - cumulativeOffset[1];
8351
+
8352
+ if (self.canvas) {
8353
+ if (self.canvas.offsetWidth) mouse.x = mouse.x / self.canvas.offsetWidth * self.canvas.width;
8354
+ if (self.canvas.offsetHeight) mouse.y = mouse.y / self.canvas.offsetHeight * self.canvas.height;
8355
+ }
8356
+
7621
8357
  mouse.y = self.canvas.height - mouse.y; // invert y
7622
8358
 
7623
8359
  if (evt.type == 'mouseover') {