demos\blackmajic\canvas\js\parpevision.js
  1 /* MIT-LICENSE */
  2 /*
  3 Copyright (c) 2009 Satoshi Ueyama
  4 
  5 Permission is hereby granted, free of charge, to any person obtaining
  6 a copy of this software and associated documentation files (the
  7 "Software"), to deal in the Software without restriction, including
  8 without limitation the rights to use, copy, modify, merge, publish,
  9 distribute, sublicense, and/or sell copies of the Software, and to
 10 permit persons to whom the Software is furnished to do so, subject to
 11 the following conditions:
 12 
 13 The above copyright notice and this permission notice shall be
 14 included in all copies or substantial portions of the Software.
 15 
 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 20 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 21 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 23 */
 24 
 25 var P3D = {
 26   texture: null,
 27   g: null
 28 };
 29 
 30 P3D.clear = function(f, w, h) {
 31   var g = this.g;
 32   g.beginPath();
 33   g.fillStyle = f;
 34   g.fillRect(0, 0, w, h);
 35 
 36 }
 37 
 38 P3D.num_cmp = function(a,b){return a-b;}
 39 
 40 P3D.drawTriangle = function(poss, uvs, shade_clr) {
 41   var w = this.texture.width;
 42   var h = this.texture.height;
 43 
 44   var g = this.g;
 45   
 46   var vAd = [ poss[1].x - poss[0].x , poss[1].y - poss[0].y ];
 47   var vBd = [ poss[2].x - poss[0].x , poss[2].y - poss[0].y ];
 48 
 49   var vA = [ uvs[1].u - uvs[0].u , uvs[1].v - uvs[0].v ];
 50   var vB = [ uvs[2].u - uvs[0].u , uvs[2].v - uvs[0].v ];
 51 
 52   vA[0] *= w;
 53   vA[1] *= h;
 54 
 55   vB[0] *= w;
 56   vB[1] *= h;
 57 
 58   var m = new M22();
 59   m._11 = vA[0];
 60   m._12 = vA[1];
 61   m._21 = vB[0];
 62   m._22 = vB[1];
 63 
 64   var im = m.getInvert();
 65   if (!im) return false;
 66 
 67   var a = im._11 * vAd[0] + im._12 * vBd[0];
 68   var b = im._21 * vAd[0] + im._22 * vBd[0];
 69 
 70   var c = im._11 * vAd[1] + im._12 * vBd[1];
 71   var d = im._21 * vAd[1] + im._22 * vBd[1];
 72 
 73   var wu = uvs[0].u * w;
 74   var hv = uvs[0].v * h;
 75   var du = wu * a + hv * b;
 76   var dv = wu * c + hv * d;
 77 
 78   g.save();
 79 
 80   g.beginPath();
 81   g.moveTo(poss[0].x, poss[0].y);
 82   g.lineTo(poss[1].x, poss[1].y);
 83   g.lineTo(poss[2].x, poss[2].y);
 84   g.clip();
 85 
 86   g.transform(a, c, b, d, poss[0].x - du, poss[0].y - dv);
 87 
 88   // bounds
 89   var bx = [wu, wu+vA[0], wu+vB[0]];
 90   var by = [hv, hv+vA[1], hv+vB[1]];
 91 
 92   bx.sort(P3D.num_cmp);
 93   by.sort(P3D.num_cmp);
 94 
 95   var bw = bx[2] - bx[0];
 96   var bh = by[2] - by[0];
 97 
 98   if ((bx[0]+bw) <= (w-1)) bw++;
 99   if ((by[0]+bh) <= (h-1)) bh++;
100   if (bx[0] >= 1) {bx[0]--; bw++;}
101   if (by[0] >= 1) {by[0]--; bh++;}
102 
103   g.drawImage(this.texture, bx[0], by[0], bw, bh, bx[0], by[0], bw, bh);
104 
105   if (shade_clr) {
106     g.fillStyle = shade_clr;
107     g.fillRect(bx[0], by[0], bw, bh);
108   }
109 
110   g.restore();
111 
112   return true;
113 }
114 
115 P3D.drawTestByIndexBuffer = function(pos_buf, ix_buf, culling) {
116   var g = this.g;
117 
118   if ((ix_buf.length%3) != 0)
119     throw "invalid index buffer length!";
120 
121   var len = ix_buf.length/3;
122 
123   var i, ibase, vbase;
124   var poss = [{},{},{}];
125   g.strokeWidth = 1;
126   for (i = 0, ibase = 0;i < len;++i)
127   {
128     vbase = ix_buf[ibase++] << 2;
129     poss[0].x = pos_buf[vbase++];
130     poss[0].y = pos_buf[vbase  ];
131 
132     vbase = ix_buf[ibase++] << 2;
133     poss[1].x = pos_buf[vbase++];
134     poss[1].y = pos_buf[vbase  ];
135 
136     vbase = ix_buf[ibase++] << 2;
137     poss[2].x = pos_buf[vbase++];
138     poss[2].y = pos_buf[vbase  ];
139 
140     // z component of cross product < 0 ?
141 
142     var Ax = poss[1].x - poss[0].x;
143     var Ay = poss[1].y - poss[0].y;
144     var Cx = poss[2].x - poss[1].x;
145     var Cy = poss[2].y - poss[1].y;
146 
147     var cull = ( (((Ax * Cy) - (Ay * Cx))*culling) < 0);
148 
149     g.beginPath();
150     g.strokeStyle = cull ? "#592" : "#0f0";
151     g.moveTo(poss[0].x, poss[0].y);
152     g.lineTo(poss[1].x, poss[1].y);
153     g.lineTo(poss[2].x, poss[2].y);
154     g.lineTo(poss[0].x, poss[0].y);
155     g.stroke();
156   }
157 }
158 
159 P3D.drawByIndexBuffer = function(pos_buf, ix_buf, tx_buf, culling, z_clip) {
160   var w, h;
161   var color_polygon = !this.texture;
162   if (this.texture) {
163     w = this.texture.width;
164     h = this.texture.height;
165   }
166 
167   var g = this.g;
168   var m = new M22();
169 
170   if (!culling) culling = 0;
171 
172   if ((ix_buf.length%3) != 0)
173     throw "invalid index buffer length!";
174 
175   var i, ibase, vbase, tbase, poss = [{},{},{}];
176   var len = ix_buf.length/3;
177   var uv_0u, uv_0v, uv_1u, uv_1v, uv_2u, uv_2v;
178 
179   for (i = 0, ibase = 0;i < len;++i)
180   {
181     tbase = ix_buf[ibase++] << 1
182     vbase = tbase << 1;
183     poss[0].x = pos_buf[vbase++]; uv_0u = tx_buf[tbase++];
184     poss[0].y = pos_buf[vbase++]; uv_0v = tx_buf[tbase];
185     if (z_clip && (pos_buf[vbase] < 0 || pos_buf[vbase] > 1)) {ibase += 2; continue;}
186 
187     tbase = ix_buf[ibase++] << 1
188     vbase = tbase << 1;
189     poss[1].x = pos_buf[vbase++]; uv_1u = tx_buf[tbase++];
190     poss[1].y = pos_buf[vbase++]; uv_1v = tx_buf[tbase];
191     if (z_clip && (pos_buf[vbase] < 0 || pos_buf[vbase] > 1)) {++ibase; continue;}
192 
193     tbase = ix_buf[ibase++] << 1
194     vbase = tbase << 1;
195     poss[2].x = pos_buf[vbase++]; uv_2u = tx_buf[tbase++];
196     poss[2].y = pos_buf[vbase++]; uv_2v = tx_buf[tbase];
197     if (z_clip && (pos_buf[vbase] < 0 || pos_buf[vbase] > 1)) {continue;}
198 
199     var vAd = [ poss[1].x - poss[0].x , poss[1].y - poss[0].y ];
200     var vBd = [ poss[2].x - poss[0].x , poss[2].y - poss[0].y ];
201 
202     var vCd = [ poss[2].x - poss[1].x , poss[2].y - poss[1].y ];
203     
204     // z component of cross product < 0 ?
205     if( (((vAd[0] * vCd[1]) - (vAd[1] * vCd[0]))*culling) < 0)
206       continue;
207 
208     if (color_polygon) {
209       g.fillStyle = uv_0u;
210 
211       g.beginPath();
212       g.moveTo(poss[0].x, poss[0].y);
213       g.lineTo(poss[1].x, poss[1].y);
214       g.lineTo(poss[2].x, poss[2].y);
215       g.fill();
216       continue;
217     }
218 
219     var vA = [ uv_1u - uv_0u , uv_1v - uv_0v ];
220     var vB = [ uv_2u - uv_0u , uv_2v - uv_0v ];
221 
222     vA[0] *= w;
223     vA[1] *= h;
224 
225     vB[0] *= w;
226     vB[1] *= h;
227 
228     m._11 = vA[0];
229     m._12 = vA[1];
230     m._21 = vB[0];
231     m._22 = vB[1];
232 
233     var im = m.getInvert();
234     if (!im) { continue;}
235 
236     var a = im._11 * vAd[0] + im._12 * vBd[0];
237     var b = im._21 * vAd[0] + im._22 * vBd[0];
238 
239     var c = im._11 * vAd[1] + im._12 * vBd[1];
240     var d = im._21 * vAd[1] + im._22 * vBd[1];
241 
242     var wu = uv_0u * w;
243     var hv = uv_0v * h;
244     var du = wu * a + hv * b;
245     var dv = wu * c + hv * d;
246 
247     g.save();
248 
249     g.beginPath();
250     g.moveTo(poss[0].x, poss[0].y);
251     g.lineTo(poss[1].x, poss[1].y);
252     g.lineTo(poss[2].x, poss[2].y);
253     g.clip();
254     g.transform(a, c, b, d, poss[0].x - du, poss[0].y - dv);
255 
256     // bounds
257     var bx = [wu, wu+vA[0], wu+vB[0]];
258     var by = [hv, hv+vA[1], hv+vB[1]];
259 
260     bx.sort(P3D.num_cmp);
261     by.sort(P3D.num_cmp);
262 
263     var bw = bx[2] - bx[0];
264     var bh = by[2] - by[0];
265 
266     if ((bx[0]+bw) <= (w-1)) bw++;
267     if ((by[0]+bh) <= (h-1)) bh++;
268     if (bx[0] >= 1) {bx[0]--; bw++;}
269     if (by[0] >= 1) {by[0]--; bh++;}
270 
271     g.drawImage(this.texture, bx[0], by[0], bw, bh, bx[0], by[0], bw, bh);
272 /*
273     if (shade_clr) {
274       g.fillStyle = shade_clr;
275       g.fillRect(bx[0], by[0], bw, bh);
276     }
277 */
278     g.restore();
279 
280   }
281 
282 }
283 
284 function Vec3(_x, _y, _z)
285 {
286   this.x = _x || 0;
287   this.y = _y || 0;
288   this.z = _z || 0;
289 }
290 
291 Vec3.prototype = {
292   zero: function() {
293     this.x = this.y = this.z = 0;
294   },
295 
296   sub: function(v) {
297     this.x -= v.x;
298     this.y -= v.y;
299     this.z -= v.z;
300 
301     return this;
302   },
303 
304   add: function(v) {
305     this.x += v.x;
306     this.y += v.y;
307     this.z += v.z;
308 
309     return this;
310   },
311 
312   copyFrom: function(v) {
313     this.x = v.x;
314     this.y = v.y;
315     this.z = v.z;
316 
317     return this;
318   },
319 
320   norm:function() {
321     return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
322   },
323 
324   normalize: function() {
325     var nrm = Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
326     if (nrm != 0)
327     {
328       this.x /= nrm;
329       this.y /= nrm;
330       this.z /= nrm;
331     }
332     return this;
333   },
334 
335   smul: function(k) {
336     this.x *= k;
337     this.y *= k;
338     this.z *= k;
339 
340     return this;
341   },
342 
343   dpWith: function(v) {
344     return this.x*v.x + this.y*v.y + this.z*v.z;
345   },
346 
347   cp: function(v, w) {
348     this.x = (w.y * v.z) - (w.z * v.y);
349     this.y = (w.z * v.x) - (w.x * v.z);
350     this.z = (w.x * v.y) - (w.y * v.x);
351 
352     return this;
353   },
354 
355   toString: function() {
356     return this.x + ", " + this.y + "," + this.z;
357   }
358 }
359 
360 function M44(cpy)
361 {
362   if (cpy)
363     this.copyFrom(cpy);
364   else {
365     this.ident();
366   }
367 }
368 
369 M44.prototype = {
370   ident: function() {
371         this._12 = this._13 = this._14 = 0;
372     this._21 =       this._23 = this._24 = 0;
373     this._31 = this._32 =       this._34 = 0;
374     this._41 = this._42 = this._43 =       0;
375 
376     this._11 = this._22 = this._33 = this._44 = 1;
377 
378     return this;
379   },
380 
381   copyFrom: function(m) {
382     this._11 = m._11;
383     this._12 = m._12;
384     this._13 = m._13;
385     this._14 = m._14;
386 
387     this._21 = m._21;
388     this._22 = m._22;
389     this._23 = m._23;
390     this._24 = m._24;
391 
392     this._31 = m._31;
393     this._32 = m._32;
394     this._33 = m._33;
395     this._34 = m._34;
396 
397     this._41 = m._41;
398     this._42 = m._42;
399     this._43 = m._43;
400     this._44 = m._44;
401 
402     return this;
403   },
404 
405   transVec3: function(out, x, y, z) {
406     out[0] = x * this._11 + y * this._21 + z * this._31 + this._41;
407     out[1] = x * this._12 + y * this._22 + z * this._32 + this._42;
408     out[2] = x * this._13 + y * this._23 + z * this._33 + this._43;
409     out[3] = x * this._14 + y * this._24 + z * this._34 + this._44;
410   },
411 
412   transVec3Rot: function(out, x, y, z) {
413     out[0] = x * this._11 + y * this._21 + z * this._31;
414     out[1] = x * this._12 + y * this._22 + z * this._32;
415     out[2] = x * this._13 + y * this._23 + z * this._33;
416   },
417 
418   perspectiveLH: function(vw, vh, z_near, z_far) {
419     this._11 = 2.0*z_near/vw;
420     this._12 = 0;
421     this._13 = 0;
422     this._14 = 0;
423 
424     this._21 = 0;
425     this._22 = 2*z_near/vh;
426     this._23 = 0;
427     this._24 = 0;
428 
429     this._31 = 0;
430     this._32 = 0;
431     this._33 = z_far/(z_far-z_near);
432     this._34 = 1;
433 
434     this._41 = 0;
435     this._42 = 0;
436     this._43 = z_near*z_far/(z_near-z_far);
437     this._44 = 0;
438 
439     return this;
440   },
441 
442   lookAtLH: function(aUp, aFrom, aAt) {
443     var aX = new Vec3();
444     var aY = new Vec3();
445   
446     var aZ = new Vec3(aAt.x, aAt.y, aAt.z);
447     aZ.sub(aFrom).normalize();
448   
449     aX.cp(aUp, aZ).normalize();
450     aY.cp(aZ, aX);
451   
452     this._11 = aX.x;  this._12 = aY.x;  this._13 = aZ.x;  this._14 = 0;
453     this._21 = aX.y;  this._22 = aY.y;  this._23 = aZ.y;  this._24 = 0;
454     this._31 = aX.z;  this._32 = aY.z;  this._33 = aZ.z;  this._34 = 0;
455   
456     this._41 = -aFrom.dpWith(aX);
457     this._42 = -aFrom.dpWith(aY);
458     this._43 = -aFrom.dpWith(aZ);
459     this._44 = 1;
460   
461       return this;
462   },
463 
464   mul: function(A, B) {
465     this._11 = A._11*B._11  +  A._12*B._21  +  A._13*B._31  +  A._14*B._41;
466     this._12 = A._11*B._12  +  A._12*B._22  +  A._13*B._32  +  A._14*B._42;
467     this._13 = A._11*B._13  +  A._12*B._23  +  A._13*B._33  +  A._14*B._43;
468     this._14 = A._11*B._14  +  A._12*B._24  +  A._13*B._34  +  A._14*B._44;
469 
470     this._21 = A._21*B._11  +  A._22*B._21  +  A._23*B._31  +  A._24*B._41;
471     this._22 = A._21*B._12  +  A._22*B._22  +  A._23*B._32  +  A._24*B._42;
472     this._23 = A._21*B._13  +  A._22*B._23  +  A._23*B._33  +  A._24*B._43;
473     this._24 = A._21*B._14  +  A._22*B._24  +  A._23*B._34  +  A._24*B._44;
474 
475     this._31 = A._31*B._11  +  A._32*B._21  +  A._33*B._31  +  A._34*B._41;
476     this._32 = A._31*B._12  +  A._32*B._22  +  A._33*B._32  +  A._34*B._42;
477     this._33 = A._31*B._13  +  A._32*B._23  +  A._33*B._33  +  A._34*B._43;
478     this._34 = A._31*B._14  +  A._32*B._24  +  A._33*B._34  +  A._34*B._44;
479 
480     this._41 = A._41*B._11  +  A._42*B._21  +  A._43*B._31  +  A._44*B._41;
481     this._42 = A._41*B._12  +  A._42*B._22  +  A._43*B._32  +  A._44*B._42;
482     this._43 = A._41*B._13  +  A._42*B._23  +  A._43*B._33  +  A._44*B._43;
483     this._44 = A._41*B._14  +  A._42*B._24  +  A._43*B._34  +  A._44*B._44;
484 
485     return this;
486   },
487 
488   translate: function(x, y, z) {
489     this._11 = 1;  this._12 = 0;  this._13 = 0;  this._14 = 0;
490     this._21 = 0;  this._22 = 1;  this._23 = 0;  this._24 = 0;
491     this._31 = 0;  this._32 = 0;  this._33 = 1;  this._34 = 0;
492 
493     this._41 = x;  this._42 = y;  this._43 = z;  this._44 = 1;
494     return this;
495   },
496 
497   transpose33: function() {
498     var t;
499 
500     t = this._12;
501     this._12 = this._21;
502     this._21 = t;
503 
504     t = this._13;
505     this._13 = this._31;
506     this._31 = t;
507 
508     t = this._23;
509     this._23 = this._32;
510     this._32 = t;
511 
512     return this;
513   },
514 
515   // OpenGL style rotation
516   glRotate: function(angle, x, y, z) {
517     var s = Math.sin( angle );
518     var c = Math.cos( angle );
519 
520     var xx = x * x;
521     var yy = y * y;
522     var zz = z * z;
523     var xy = x * y;
524     var yz = y * z;
525     var zx = z * x;
526     var xs = x * s;
527     var ys = y * s;
528     var zs = z * s;
529     var one_c = 1.0 - c;
530 /*
531     this._11 = (one_c * xx) + c;
532     this._21 = (one_c * xy) - zs;
533     this._31 = (one_c * zx) + ys;
534     this._41 = 0;
535 
536     this._12 = (one_c * xy) + zs;
537     this._22 = (one_c * yy) + c;
538     this._32 = (one_c * yz) - xs;
539     this._42 = 0;
540 
541     this._13 = (one_c * zx) - ys;
542     this._23 = (one_c * yz) + xs;
543     this._33 = (one_c * zz) + c;
544     this._43 = 0;
545 
546     this._14 = 0;
547     this._24 = 0;
548     this._34 = 0;
549     this._44 = 1;
550 */
551 
552     this._11 = (one_c * xx) + c;
553     this._12 = (one_c * xy) - zs;
554     this._13 = (one_c * zx) + ys;
555     this._14 = 0;
556 
557     this._21 = (one_c * xy) + zs;
558     this._22 = (one_c * yy) + c;
559     this._23 = (one_c * yz) - xs;
560     this._24 = 0;
561 
562     this._31 = (one_c * zx) - ys;
563     this._32 = (one_c * yz) + xs;
564     this._33 = (one_c * zz) + c;
565     this._34 = 0;
566 
567     this._41 = 0;
568     this._42 = 0;
569     this._43 = 0;
570     this._44 = 1;
571 
572     return this;
573   }
574 
575 }
576 
577 // matrix 2x2
578 function M22()
579 {
580   this._11 = 1;
581   this._12 = 0;
582   this._21 = 0;
583   this._22 = 1;
584 }
585 
586 M22.prototype.getInvert = function()
587 {
588   var out = new M22();
589   var det = this._11 * this._22 - this._12 * this._21;
590   if (det > -0.0001 && det < 0.0001)
591     return null;
592 
593   out._11 = this._22 / det;
594   out._22 = this._11 / det;
595 
596   out._12 = -this._12 / det;
597   out._21 = -this._21 / det;
598 
599   return out;
600 } 
601 
602