jax 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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') {