-//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);\r
-//>>description: Tizen motion path component for gallery3d\r
-//>>label: Motion path\r
-//>>group: Tizen:Widgets:Components\r
-\r
-define( [ ], function ( ) {\r
-//>>excludeEnd("jqmBuildExclude");\r
-\r
-/* ***************************************************************************\r
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a\r
- * copy of this software and associated documentation files (the "Software"),\r
- * to deal in the Software without restriction, including without limitation\r
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
- * and/or sell copies of the Software, and to permit persons to whom the\r
- * Software is furnished to do so, subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in\r
- * all copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
- * DEALINGS IN THE SOFTWARE.\r
- * ***************************************************************************\r
- *\r
- * Authors: Hyunsook Park <hyunsook.park@samsung.com>\r
- * Wonseop Kim <wonseop.kim@samsung.com>\r
-*/\r
-\r
-( function ( $, window, undefined ) {\r
- var HALF_PI = Math.PI / 2,\r
- DEFAULT_STEP = 0.001,\r
- MotionPath = {},\r
- vec3 = window.vec3,\r
- arcLength2d = function ( p0, p1 ) {\r
- var d = [ p1[0] - p0[0], p1[1] - p0[1] ],\r
- value = Math.sqrt( d[0] * d[0] + d[1] * d[1] );\r
- return value;\r
- },\r
- arcLength3d = function ( p0, p1 ) {\r
- var d = [ p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] ],\r
- value = Math.sqrt( d[0] * d[0] + d[1] * d[1] + d[2] * d[2] );\r
- return value;\r
- };\r
-\r
- MotionPath.base = function () {};\r
- MotionPath.base.prototype = {\r
- points: [],\r
- step: DEFAULT_STEP,\r
- length: 0,\r
- levels: [],\r
- init: function ( data ) {},\r
- calculateLevel: function ( maxLevel ) {},\r
- calculateTotalLength: function () {},\r
- getPosition: function ( percent ) {},\r
- getPercent: function ( start, interval ) {},\r
- getAngle: function ( percent ) {}\r
- };\r
-\r
- MotionPath.bezier2d = function () {};\r
- MotionPath.bezier2d.prototype = $.extend( true, {}, MotionPath.base.prototype, {\r
- init: function ( data ) {\r
- this.points = data.points;\r
- this.step = data.step || DEFAULT_STEP;\r
- this.length = this.calculateTotalLength();\r
- this.levels = this.calculateLevel( data.maxLevel ) || [];\r
- },\r
-\r
- calculateLevel: function ( maxLevel ) {\r
- var totalLength = this.length,\r
- interval = totalLength / maxLevel,\r
- levels = [],\r
- i;\r
-\r
- if ( !maxLevel ) {\r
- return null;\r
- }\r
-\r
- for ( i = 0; i < maxLevel; i += 1 ) {\r
- levels[maxLevel - i] = this.getPercent( 0, interval * i );\r
- }\r
-\r
- return levels;\r
- },\r
-\r
- calculateTotalLength: function () {\r
- var step = this.step,\r
- current = this.getPosition( 0 ),\r
- last = current,\r
- length = 0,\r
- percent;\r
- for ( percent = step; percent <= 1; percent += step ) {\r
- current = this.getPosition( percent );\r
- length += arcLength2d( last, current );\r
- last = current;\r
- }\r
- return length;\r
- },\r
-\r
- getPosition: function ( percent ) {\r
- var points = this.points,\r
- getValue = function ( p1, c1, c2, p2, t ) {\r
- return Math.pow(1 - t, 3) * p1 +\r
- 3 * t * Math.pow( 1 - t, 2 ) * c1 +\r
- 3 * Math.pow( t, 2 ) * ( 1 - t ) * c2 +\r
- Math.pow( t, 3 ) * p2;\r
- },\r
- result = [\r
- getValue( points[0][0], points[1][0], points[2][0], points[3][0], percent ),\r
- getValue( points[0][1], points[1][1], points[2][1], points[3][1], percent )\r
- ];\r
- return result;\r
- },\r
-\r
- getPercent: function ( start, interval ) {\r
- var step = this.step,\r
- current = this.getPosition( start = start || 0 ),\r
- last = current,\r
- targetLength = start + interval,\r
- length = 0,\r
- percent;\r
-\r
- for ( percent = start + step; percent <= 1; percent += step ) {\r
- current = this.getPosition( percent );\r
- length += arcLength2d( last, current );\r
- if ( length >= targetLength ) {\r
- return percent;\r
- }\r
- last = current;\r
- }\r
- return 1;\r
- },\r
-\r
- getAngle: function ( percent ) {\r
- var points = this.points,\r
- getTangent = function ( p1, c1, c2, p2, t ) {\r
- return 3 * t * t * ( -p1 + 3 * c1 - 3 * c2 + p2 ) + 6 * t * ( p1 - 2 * c1 + c2 ) + 3 * ( -p1 + c1 );\r
- },\r
- tx = getTangent( points[0][0], points[1][0], points[2][0], points[3][0], percent ),\r
- ty = getTangent( points[0][1], points[1][1], points[2][1], points[3][1], percent );\r
- return Math.atan2( tx, ty ) - HALF_PI;\r
- }\r
-\r
- } );\r
-\r
- // clamped cubic B-spline curve\r
- // http://web.mit.edu/hyperbook/Patrikalakis-Maekawa-Cho/node17.html\r
- // http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/B-spline/bspline-curve-coef.html\r
- MotionPath.bspline = function () {};\r
- MotionPath.bspline.prototype = $.extend( true, {}, MotionPath.base.prototype, {\r
- _degree: 3,\r
- _numberOfControls : 0,\r
- _knotVectors: [],\r
- _numberOfKnots: 0,\r
-\r
- init: function ( data ) {\r
- this.points = data.points;\r
- this.step = data.step || DEFAULT_STEP;\r
- this._numberOfPoints = this.points.length - 1;\r
- this._numberOfKnots = this._numberOfPoints + this._degree + 1;\r
-\r
- var deltaKnot = 1 / ( this._numberOfKnots - ( 2 * this._degree ) ),\r
- v = deltaKnot,\r
- i = 0;\r
-\r
- while ( i <= this._numberOfKnots ) {\r
- if ( i <= this._degree ) {\r
- this._knotVectors.push( 0 );\r
- } else if ( i < this._numberOfKnots - this._degree + 1 ) {\r
- this._knotVectors.push( v );\r
- v += deltaKnot;\r
- } else {\r
- this._knotVectors.push( 1 );\r
- }\r
- i += 1;\r
- }\r
-\r
- this.length = this.calculateTotalLength();\r
- this.levels = this.calculateLevel( data.maxLevel ) || [];\r
- },\r
-\r
- _Np: function ( percent, i, degree ) {\r
- var knots = this._knotVectors,\r
- A = 0,\r
- B = 0,\r
- denominator = 0,\r
- N0 = function ( percent, i ) {\r
- return ( ( knots[i] <= percent && percent < knots[i + 1] ) ? 1 : 0 );\r
- };\r
-\r
- if ( degree === 1 ) {\r
- A = N0( percent, i );\r
- B = N0( percent, i + 1 );\r
- } else {\r
- A = this._Np( percent, i, degree - 1 );\r
- B = this._Np( percent, i + 1, degree - 1 );\r
- }\r
-\r
- denominator = knots[i + degree] - knots[i];\r
- A *= ( denominator !== 0 ) ? ( ( percent - knots[i] ) / denominator ) : 0;\r
- denominator = knots[i + degree + 1] - knots[i + 1];\r
- B *= ( denominator !== 0 ) ? ( ( knots[i + degree + 1] - percent ) / denominator ) : 0;\r
-\r
- return A + B;\r
- },\r
-\r
- calculateLevel: function ( maxLevel ) {\r
- var totalLength = this.length,\r
- interval = totalLength / maxLevel,\r
- levels = [],\r
- i;\r
-\r
- if ( !maxLevel ) {\r
- return null;\r
- }\r
-\r
- for ( i = 0; i < maxLevel; i += 1 ) {\r
- levels[maxLevel - i] = this.getPercent( 0, interval * i );\r
- }\r
- return levels;\r
- },\r
-\r
- calculateTotalLength: function () {\r
- var step = this.step,\r
- current = this.getPosition( 0 ),\r
- last = current,\r
- length = 0,\r
- percent;\r
- for ( percent = step; percent <= 1; percent += step ) {\r
- current = this.getPosition( percent );\r
- length += arcLength3d( last, current );\r
- last = current;\r
- }\r
- return length;\r
- },\r
-\r
- getPosition: function ( percent ) {\r
- var result = [], i, j, sum;\r
- percent = percent.toFixed( 4 );\r
- for ( j = 0; j < 3; j += 1 ) {\r
- sum = 0;\r
- for ( i = 0; i <= this._numberOfPoints; i += 1 ) {\r
- sum += this.points[i][j] * this._Np( percent, i, this._degree );\r
- }\r
- result[j] = sum;\r
- }\r
-\r
- return result;\r
- },\r
-\r
- getPercent: function ( start, interval ) {\r
- var step = this.step,\r
- current = this.getPosition( start = start || 0 ),\r
- last = current,\r
- targetLength = start + interval,\r
- length = 0,\r
- percent;\r
-\r
- for ( percent = start + step; percent <= 1; percent += step ) {\r
- current = this.getPosition( percent );\r
- length += arcLength3d( last, current );\r
- if ( length >= targetLength ) {\r
- return percent;\r
- }\r
- last = current;\r
- }\r
- return 1;\r
- },\r
-\r
- getAngle: function ( percent ) {\r
- var prev = this.getPosition( percent ),\r
- next = this.getPosition( percent + 0.001 ),\r
- dir = vec3.normalize( vec3.direction( prev, next ) ),\r
- cosValue = vec3.dot( dir, [1, 0, 0] );\r
-\r
- return Math.acos( cosValue ) + Math.PI;\r
- }\r
- } );\r
-\r
- $.motionpath = function ( type, data ) {\r
- var object = new MotionPath[type]();\r
- object.init( data );\r
- return object;\r
- };\r
-} ( jQuery, window ) );\r
-\r
-//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);\r
-} );\r
-//>>excludeEnd("jqmBuildExclude");\r
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+//>>description: Tizen motion path component for gallery3d
+//>>label: Motion path
+//>>group: Tizen:Widgets:Components
+
+define( [ ], function ( ) {
+//>>excludeEnd("jqmBuildExclude");
+
+/* ***************************************************************************
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * ***************************************************************************
+ *
+ * Authors: Hyunsook Park <hyunsook.park@samsung.com>
+ * Wonseop Kim <wonseop.kim@samsung.com>
+*/
+
+( function ( $, window, undefined ) {
+ var HALF_PI = Math.PI / 2,
+ DEFAULT_STEP = 0.001,
+ MotionPath = {},
+ vec3 = window.vec3,
+ arcLength3d = function ( p0, p1 ) {
+ var d = [ p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] ],
+ value = Math.sqrt( d[0] * d[0] + d[1] * d[1] + d[2] * d[2] );
+ return value;
+ };
+
+ MotionPath.base = function () {};
+ MotionPath.base.prototype = {
+ points: [],
+ step: DEFAULT_STEP,
+ length: 0,
+ levels: [],
+ init: function ( data ) {},
+ calculateLevel: function ( maxLevel ) {},
+ calculateTotalLength: function () {},
+ getPosition: function ( percent ) {},
+ getPercent: function ( start, interval ) {},
+ getAngle: function ( percent ) {}
+ };
+
+ MotionPath.bezier2d = function () {};
+ MotionPath.bezier2d.prototype = $.extend( true, {}, MotionPath.base.prototype, {
+ init: function ( data ) {
+ this.points = data.points;
+ this.step = data.step || DEFAULT_STEP;
+ this.length = this.calculateTotalLength();
+ this.levels = this.calculateLevel( data.maxLevel ) || [];
+ },
+
+ calculateLevel: function ( maxLevel ) {
+ var totalLength = this.length,
+ interval = totalLength / maxLevel,
+ levels = [],
+ i;
+
+ if ( !maxLevel ) {
+ return null;
+ }
+
+ for ( i = 0; i < maxLevel; i += 1 ) {
+ levels[maxLevel - i] = this.getPercent( 0, interval * i );
+ }
+
+ return levels;
+ },
+
+ calculateTotalLength: function () {
+ var step = this.step,
+ current = this.getPosition( 0 ),
+ last = current,
+ length = 0,
+ percent;
+ for ( percent = step; percent <= 1; percent += step ) {
+ current = this.getPosition( percent );
+ length += arcLength3d( last, current );
+ last = current;
+ }
+ return length;
+ },
+
+ getPosition: function ( percent ) {
+ var points = this.points,
+ getValue = function ( p1, c1, c2, p2, t ) {
+ return Math.pow(1 - t, 3) * p1 +
+ 3 * t * Math.pow( 1 - t, 2 ) * c1 +
+ 3 * Math.pow( t, 2 ) * ( 1 - t ) * c2 +
+ Math.pow( t, 3 ) * p2;
+ },
+ result = [
+ getValue( points[0][0], points[1][0], points[2][0], points[3][0], percent ),
+ getValue( points[0][2], points[1][2], points[2][2], points[3][2], percent )
+ ];
+ return [ result[0], 0, result[1] ];
+ },
+
+ getPercent: function ( start, interval ) {
+ var step = this.step,
+ current = this.getPosition( start = start || 0 ),
+ last = current,
+ targetLength = start + interval,
+ length = 0,
+ percent;
+
+ for ( percent = start + step; percent <= 1; percent += step ) {
+ current = this.getPosition( percent );
+ length += arcLength3d( last, current );
+ if ( length >= targetLength ) {
+ return percent;
+ }
+ last = current;
+ }
+ return 1;
+ },
+
+ getAngle: function ( percent ) {
+ var points = this.points,
+ getTangent = function ( p1, c1, c2, p2, t ) {
+ return 3 * t * t * ( -p1 + 3 * c1 - 3 * c2 + p2 ) + 6 * t * ( p1 - 2 * c1 + c2 ) + 3 * ( -p1 + c1 );
+ },
+ tx = getTangent( points[0][0], points[1][0], points[2][0], points[3][0], percent ),
+ ty = getTangent( points[0][2], points[1][2], points[2][2], points[3][2], percent );
+ return Math.atan2( tx, ty ) - HALF_PI;
+ }
+
+ } );
+
+ // clamped cubic B-spline curve
+ // http://web.mit.edu/hyperbook/Patrikalakis-Maekawa-Cho/node17.html
+ // http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/B-spline/bspline-curve-coef.html
+ MotionPath.bspline = function () {};
+ MotionPath.bspline.prototype = $.extend( true, {}, MotionPath.base.prototype, {
+ _degree: 3,
+ _numberOfControls : 0,
+ _knotVectors: [],
+ _numberOfKnots: 0,
+
+ init: function ( data ) {
+ this.points = data.points;
+ this.step = data.step || DEFAULT_STEP;
+ this._numberOfPoints = this.points.length - 1;
+ this._numberOfKnots = this._numberOfPoints + this._degree + 1;
+
+ var deltaKnot = 1 / ( this._numberOfKnots - ( 2 * this._degree ) ),
+ v = deltaKnot,
+ i = 0;
+
+ while ( i <= this._numberOfKnots ) {
+ if ( i <= this._degree ) {
+ this._knotVectors.push( 0 );
+ } else if ( i < this._numberOfKnots - this._degree + 1 ) {
+ this._knotVectors.push( v );
+ v += deltaKnot;
+ } else {
+ this._knotVectors.push( 1 );
+ }
+ i += 1;
+ }
+
+ this.length = this.calculateTotalLength();
+ this.levels = this.calculateLevel( data.maxLevel ) || [];
+ },
+
+ _Np: function ( percent, i, degree ) {
+ var knots = this._knotVectors,
+ A = 0,
+ B = 0,
+ denominator = 0,
+ N0 = function ( percent, i ) {
+ return ( ( knots[i] <= percent && percent < knots[i + 1] ) ? 1 : 0 );
+ };
+
+ if ( degree === 1 ) {
+ A = N0( percent, i );
+ B = N0( percent, i + 1 );
+ } else {
+ A = this._Np( percent, i, degree - 1 );
+ B = this._Np( percent, i + 1, degree - 1 );
+ }
+
+ denominator = knots[i + degree] - knots[i];
+ A *= ( denominator !== 0 ) ? ( ( percent - knots[i] ) / denominator ) : 0;
+ denominator = knots[i + degree + 1] - knots[i + 1];
+ B *= ( denominator !== 0 ) ? ( ( knots[i + degree + 1] - percent ) / denominator ) : 0;
+
+ return A + B;
+ },
+
+ calculateLevel: function ( maxLevel ) {
+ var totalLength = this.length,
+ interval = totalLength / maxLevel,
+ levels = [],
+ i;
+
+ if ( !maxLevel ) {
+ return null;
+ }
+
+ for ( i = 0; i < maxLevel; i += 1 ) {
+ levels[maxLevel - i] = this.getPercent( 0, interval * i );
+ }
+ return levels;
+ },
+
+ calculateTotalLength: function () {
+ var step = this.step,
+ current = this.getPosition( 0 ),
+ last = current,
+ length = 0,
+ percent;
+ for ( percent = step; percent <= 1; percent += step ) {
+ current = this.getPosition( percent );
+ length += arcLength3d( last, current );
+ last = current;
+ }
+ return length;
+ },
+
+ getPosition: function ( percent ) {
+ var result = [], i, j, sum;
+ percent = percent.toFixed( 4 );
+ for ( j = 0; j < 3; j += 1 ) {
+ sum = 0;
+ for ( i = 0; i <= this._numberOfPoints; i += 1 ) {
+ sum += this.points[i][j] * this._Np( percent, i, this._degree );
+ }
+ result[j] = sum;
+ }
+
+ return result;
+ },
+
+ getPercent: function ( start, interval ) {
+ var step = this.step,
+ current = this.getPosition( start = start || 0 ),
+ last = current,
+ targetLength = start + interval,
+ length = 0,
+ percent;
+
+ for ( percent = start + step; percent <= 1; percent += step ) {
+ current = this.getPosition( percent );
+ length += arcLength3d( last, current );
+ if ( length >= targetLength ) {
+ return percent;
+ }
+ last = current;
+ }
+ return 1;
+ },
+
+ getAngle: function ( percent ) {
+ var prev = this.getPosition( percent ),
+ next = this.getPosition( percent + 0.001 ),
+ dir = vec3.normalize( vec3.direction( prev, next ) ),
+ cosValue = vec3.dot( dir, [1, 0, 0] );
+
+ return Math.acos( cosValue ) + Math.PI;
+ }
+ } );
+
+ $.motionpath = function ( type, data ) {
+ var object = new MotionPath[type]();
+ object.init( data );
+ return object;
+ };
+} ( jQuery, window ) );
+
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+} );
+//>>excludeEnd("jqmBuildExclude");
-//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);\r
-//>>description: 3D photo gallery widget.\r
-//>>label: Gallery3d\r
-//>>group: Tizen:Widgets\r
-\r
-define( [ "components/imageloader", "components/motionpath", "components/webgl" ], function ( ) {\r
-//>>excludeEnd("jqmBuildExclude");\r
-\r
-\r
-/* ***************************************************************************\r
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a\r
- * copy of this software and associated documentation files (the "Software"),\r
- * to deal in the Software without restriction, including without limitation\r
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
- * and/or sell copies of the Software, and to permit persons to whom the\r
- * Software is furnished to do so, subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in\r
- * all copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\r
- * DEALINGS IN THE SOFTWARE.\r
- * ***************************************************************************\r
- *\r
- * Authors: Hyunsook Park <hyunsook.park@samsung.com>\r
- * Wonseop Kim <wonseop.kim@samsung.com>\r
- */\r
-\r
-/**\r
- * 'Gallery3D' is a 3D photo gallery widget.\r
- * Images are arranged with a S-shaped curve on a 3-dimensional coordinate system.\r
- * A user can rotate images by swiping the widget area.\r
- * To improve performance, the size of image(s) displayed on the screen should be a square(under\r
- * 128X128 pixel) as possible. But if a user can't resize the images, this widget supports an image\r
- * resizing feature and he/she can use it with "data-thumbnail-cache" option. ("data-thumbnail-cache"\r
- * option resizes the gallery images under 128x128 pixels and stores the images on a local storage.\r
- * So when a gallery3D widget is re-launched, the widget reuse the storage and a user can improve\r
- * launching time. A browser or web runtime engine should support "Web Storage" feature to use that\r
- * option.)\r
- *\r
- * HTML Attributes:\r
- *\r
- * data-thumbnail-cache : Determines whether to cache and resize images.\r
- *\r
- * APIs:\r
- *\r
- * next ( void )\r
- * : This method moves each image forward one by one.\r
- * prev ( void )\r
- * : This method moves each image backward one by one.\r
- * select ( [number] )\r
- * : When the "select" method is called with an argument, the method selects the image of given index.\r
- * If the method is called with no argument, it will return the Javascript object having "src"\r
- * attribute having the selected image’s URL.\r
- * add ( object or string [, number] )\r
- * This method adds an image to Gallery3D widget.\r
- * If the second argument isn't inputted, the image is added at the 0th position.\r
- * remove ( [number] )\r
- * : This method deletes an image from Gallery3d widget.\r
- * The argument defines the index of the image to be deleted.\r
- * If an argument isn't inputted, it removes current image.\r
- * clearThumbnailCache ( void )\r
- * : This method clears the cache data of all images when thumbnailCache option is set as 'true'.\r
- * refresh ( void )\r
- * : This method updates and redraws current widget.\r
- * empty ( void )\r
- * : This method removes all of images from Gallery3D widget.\r
- * length ( void )\r
- * : This method gets the number of images.\r
- *\r
- * Events:\r
- *\r
- * select : Triggered when an image is selected.\r
- *\r
- * Examples:\r
- *\r
- * <script>\r
- * $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- * $( "#gallery3d" ).gallery3d( "add", "01.jpg" );\r
- * });\r
- * </script>\r
- * <div id="gallery3d" data-role="gallery3d"></div>\r
- */\r
-\r
-/**\r
- @class Gallery3D\r
- The gallery3d widget is a 3D photo gallery widget.\r
- Images are arranged with a S-shaped curve on a 3-dimensional coordinate system.\r
- A user can rotate images by swiping the widget area.\r
- <br/><br/>To add an gallery3d widget to the application, use the following code:\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", "01.jpg" );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @property {Boolean} data-thumbnail-cache\r
- Determines whether to cache and resize images.\r
- To improve performance, the size of image(s) displayed on the screen should be a square (under 128X128 pixels).\r
- "data-thumbnail-cache" option resizes the gallery images under 128x128 pixels and stores the images on a local storage.\r
- So when a gallery3D widget is re-launched, the widget reuses the storage and the launching time can be improved.\r
- A browser or web runtime engine must support "Web Storage" feature to use this option.\r
-*/\r
-/**\r
- @event select\r
- Triggered when an image is selected.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } );\r
- }).on( "select", function ( event, data, index ) {\r
- // Handle the select event\r
- var urlOfImage = data.src, indexOfImage = index;\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method next\r
- This method moves each image forward one by one.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } )\r
- .gallery3d( "next" );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method prev\r
- This method moves each image backward one by one.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } )\r
- .gallery3d( "prev" );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method select\r
- When the "select" method is called with an argument, the method selects the image of given index.\r
- If the method is called with no argument, it will return the Javascript object having "src" attribute having the selected image’s URL.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } );\r
- var selectedImage = $("#gallery3d"). gallery3d( "select" );\r
- // selectedImage = { src: "3.jpg" };\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method add\r
- This method adds an image to Gallery3D widget.\r
- The first argument is a Javascript object having a "src" attribute or a string of image's path.\r
- The second argument is an index of images.\r
- If second argument isn't inputted, the image is added at the 0th position.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", "2.jpg", 1 );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method remove\r
- This method deletes an image from Gallery3d widget.\r
- The argument defines the index of the image to be deleted.\r
- If an argument isn't inputted, it removes current image.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } );\r
-\r
- $( "#gallery3d" ).gallery3d( "remove" );\r
- $( "#gallery3d" ).gallery3d( "remove", 1 );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method clearThumbnailCache\r
- This method clears the cache data of all images when thumbnailCache option is set as 'true'\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } );\r
-\r
- $( "#gallery3d" ).gallery3d( "clearThumbnailCache" );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d" data-thumbnail-cache="true"></div>\r
-*/\r
-/**\r
- @method refresh\r
- This method updates and redraws current widget.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } );\r
-\r
- $( "#gallery3d" ).gallery3d( "refresh" );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method empty\r
- This method removes all of images from Gallery3D widget.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } );\r
-\r
- $( "#gallery3d" ).gallery3d( "empty" );\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-/**\r
- @method length\r
- This method gets the number of images.\r
-\r
- <script>\r
- $( "#gallery3d" ).on( "gallery3dcreate", function () {\r
- $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )\r
- .gallery3d( "add", { src: "2.jpg" } )\r
- .gallery3d( "add", { src: "3.jpg" } );\r
-\r
- var imagesLength = $( "#gallery3d" ).gallery3d( "length" );\r
- // imagesLength = 3;\r
- });\r
- </script>\r
- <div id="gallery3d" data-role="gallery3d"></div>\r
-*/\r
-\r
-( function ( $, document, window, undefined ) {\r
- window.requestAnimationFrame = ( function () {\r
- return function ( callback ) {\r
- var id = window.setTimeout( callback, 1000 / 60 );\r
- return id;\r
- };\r
- } () );\r
-\r
- window.cancelAnimationFrame = ( function () {\r
- return function ( id ) {\r
- window.clearTimeout( id );\r
- };\r
- } () );\r
-\r
- var vec3 = window.vec3,\r
- mat3 = window.mat3,\r
- mat4 = window.mat4,\r
- GlArray32 = ( typeof window.Float32Array !== "undefined" ? window.Float32Array : ( typeof window.WebGLFloatArray !== "undefined" ? window.WebGLFloatArray : Array ) ),\r
- GlArray16 = ( typeof window.Uint16Array !== "undefined" ? window.Uint16Array : Array ),\r
- getContext3D = function ( canvas ) {\r
- var gl, i,\r
- contextNames = [ "experimental-webgl", "webkit-3d", "webgl", "moz-webgl" ];\r
-\r
- for ( i = 0; i < contextNames.length; i += 1 ) {\r
- try {\r
- gl = canvas.getContext( contextNames[i] );\r
- if ( gl ) {\r
- break;\r
- }\r
- } catch ( e ) {\r
- window.alert( "Unfortunately, there's a WebGL compatibility problem. </br> You may want to check your system settings." );\r
- return;\r
- }\r
- }\r
- return gl;\r
- },\r
- VERTEX_SHADER = [\r
- "attribute vec3 aVertexPosition;",\r
- "attribute vec2 aTextureCoord;",\r
- "attribute vec3 aVertexNormal;",\r
- "uniform mat4 uMoveMatrix;",\r
- "uniform mat4 uPerspectiveMatrix;",\r
- "uniform mat3 nNormalMatrix;",\r
- "uniform vec3 uAmbientColor;",\r
- "uniform vec3 uLightDirection;",\r
- "uniform vec3 uDirectionColor;",\r
- "uniform vec3 uLightDirection_first;",\r
- "uniform vec3 uLightDirection_second;",\r
- "varying vec2 vTextureCoord;",\r
- "varying vec3 vLightWeight;",\r
- "varying vec4 vFogWeight;",\r
-\r
- "void main(void) {",\r
- " vec4 v_Position = uMoveMatrix * vec4(aVertexPosition, 1.0);",\r
- " gl_Position = uPerspectiveMatrix * v_Position;",\r
- " vTextureCoord = aTextureCoord;",\r
- " float fog = 1.0 - ((gl_Position.z + 1.5) / 60.0);",\r
- " vFogWeight = clamp( vec4( fog, fog, fog, 1.0), 0.0, 1.0);",\r
- " vec3 transNormalVector = nNormalMatrix * aVertexNormal;",\r
-\r
- " float vLightWeightFirst = 0.0;",\r
- " float vLightWeightSecond = max( dot(transNormalVector, uLightDirection_second), 0.0 );",\r
-\r
- " vLightWeight = uAmbientColor + uDirectionColor * vLightWeightSecond;",\r
- "}"\r
- ].join( "\n" ),\r
- FRAGMENT_SHADER = [\r
- "precision mediump float;",\r
- "varying vec2 vTextureCoord;",\r
- "varying vec3 vLightWeight;",\r
- "uniform sampler2D uSampler;",\r
- "varying vec4 vFogWeight;",\r
-\r
- "void main(void) {",\r
- " vec4 TextureColor = (texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t))) * vFogWeight;",\r
- " gl_FragColor = vec4(TextureColor.rgb * vLightWeight, TextureColor.a);",\r
- "}"\r
- ].join( "\n" );\r
-\r
- function Node() {\r
- this.vertices = [\r
- -1.0, -1.0, 0.0,\r
- 1.0, -1.0, 0.0,\r
- 1.0, 1.0, 0.0,\r
- -1.0, 1.0, 0.0\r
- ];\r
- this.textureCoords = [\r
- 1.0, 0.0,\r
- 0.0, 0.0,\r
- 0.0, 1.0,\r
- 1.0, 1.0\r
- ];\r
- this.normalVectors = [\r
- 0.0, 0.0, 1.0,\r
- 0.0, 0.0, 1.0,\r
- 0.0, 0.0, 1.0,\r
- 0.0, 0.0, 1.0\r
- ];\r
- this.texture = null;\r
- this.textureBuffer = null;\r
- this.textureBufferItemSize = 0;\r
- this.mashOrder = [];\r
- this.mvMatrix = null;\r
- this.level = -1;\r
- this.targetLevel = 0;\r
- this.drawable = false;\r
- this.image = null;\r
- this.imageID = 0;\r
- }\r
-\r
- $.widget( "tizen.gallery3d", $.mobile.widget, {\r
- options: {\r
- thumbnailCache: false\r
- },\r
-\r
- _MAX_ITEM_COUNT: 28,\r
- _ANIMATION_END: 999,\r
- _DURATION_DEFAULT: 300,\r
- _DURATION_FIRST: 1600,\r
- _VIEWPORT_WIDTH: 1024,\r
- _VIEWPORT_HEIGHT: 456,\r
- _DIRECTION_LEFT: -1,\r
- _DIRECTION_RIGHT: +1,\r
-\r
- _gl: null,\r
- _shaderProgram : null,\r
- _positionBuffer : null,\r
- _textureCoordBuffer : null,\r
- _normalVectorBuffer : null,\r
- _nodes: null,\r
- _pMatrix : null,\r
- _animationID: 0,\r
- _dragInterval : 0,\r
- _startTime : 0,\r
- _sumTime : 0,\r
- _lightsPositionStack : [\r
- [0.0, 0.0, -1.0], // back\r
- [-0.2, 0.0, 0.7] // front\r
- ],\r
- _path: null,\r
- _swipeThresholdOfBasetimeGap: ( $.support.touch ? 30 : 70 ),\r
- _swipeThresholdOfSensitivity: ( $.support.touch ? 2.0 : 10.0 ),\r
- _canvas: null,\r
- _imageList: [],\r
- _maxDrawLength: 0,\r
- _firstImageNumber: 0,\r
- _lastImageNumber: 0,\r
-\r
- _create: function () {\r
- var self = this,\r
- view = self.element,\r
- option = self.options;\r
-\r
- self._canvas = $( "<canvas class='ui-gallery3d-canvas'></canvas>" );\r
-\r
- view.addClass( "ui-gallery3d" ).append( self._canvas );\r
- self._addBehavier();\r
-\r
- self._dragInterval = 1000 / 30; // 30fps\r
-\r
- $.each( self.options, function ( key, value ) {\r
- self.options[ key ] = undefined;\r
- self._setOption( key, value );\r
- });\r
-\r
- },\r
-\r
- _setOption: function ( key, value ) {\r
- switch ( key ) {\r
- case "thumbnailCache" :\r
- if ( typeof value === "string" ) {\r
- value = ( value === "true" ) ? true : false;\r
- } else {\r
- value = !!value;\r
- }\r
- this._reset();\r
- break;\r
- }\r
-\r
- $.mobile.widget.prototype._setOption.call( this, key, value );\r
- },\r
-\r
- _init: function ( canvas ) {\r
- var self = this,\r
- pathPoints = [\r
- [40, 0, -48],\r
- [-12, 0, -40], // contorl Point of Point1\r
- [24, 0, -9], // contorl Point of Point2\r
- [-5, 0, -5]\r
- ],\r
- i;\r
-\r
- canvas = canvas || self._canvas;\r
-\r
- if ( !canvas ) {\r
- return;\r
- }\r
-\r
- self._gl = self._gl || self._initGL( canvas[0] );\r
- if ( !self._gl ) {\r
- return;\r
- }\r
-\r
- if ( !self._imageList ) {\r
- return;\r
- }\r
-\r
- self._shaderProgram = self._shaderProgram || self._initShader( self._gl );\r
- if ( !self._shaderProgram ) {\r
- return;\r
- }\r
-\r
- if ( self._imageList.length > self._MAX_ITEM_COUNT ) {\r
- self._firstImageNumber = self._imageList.length - 1;\r
- self._lastImageNumber = self._MAX_ITEM_COUNT - 1;\r
- }\r
-\r
- self._nodes = self._initBuffers( self._gl, self._shaderProgram );\r
- self._initTextures( self._gl, self._nodes );\r
- self._path = $.motionpath( "bspline", {\r
- points: pathPoints,\r
- maxLevel: self._MAX_ITEM_COUNT\r
- } );\r
- for ( i = 0; i < self._nodes.length; i += 1 ) {\r
- self._path.levels[i] = self._path.levels[i + 1] || 0;\r
- self._nodes[i].level = i;\r
- }\r
- },\r
-\r
- _final: function ( canvas ) {\r
- var self = this,\r
- gl = self._gl;\r
-\r
- if ( !gl ) {\r
- return;\r
- }\r
-\r
- canvas = canvas || self._canvas;\r
-\r
- $( self._nodes ).each( function ( i ) {\r
- var node = self._nodes[i];\r
- gl.deleteTexture( node.texture );\r
- node.texture = null;\r
- });\r
- self._nodes = null;\r
-\r
- gl.deleteBuffer( self._positionBuffer );\r
- self._positionBuffer = null;\r
- gl.deleteBuffer( self._textureCoordBuffer );\r
- self._textureCoordBuffer = null;\r
- gl.deleteBuffer( self._normalVectorBuffer );\r
- self._normalVectorBuffer = null;\r
-\r
- $.webgl.shader.deleteShaders( gl );\r
- gl.deleteProgram( self._shaderProgram );\r
- self._shaderProgram = null;\r
-\r
- self._gl = gl = null;\r
- },\r
-\r
- _addBehavier : function () {\r
- var self = this,\r
- view = self.element,\r
- canvas = self._canvas,\r
- touchStartEvt = ( $.support.touch ? "touchstart" : "mousedown" ),\r
- touchMoveEvt = ( $.support.touch ? "touchmove" : "mousemove" ) + ".gallery3d",\r
- touchEndEvt = ( $.support.touch ? "touchend" : "mouseup" ) + ".gallery3d",\r
- touchLeaveEvt = ( $.support.touch ? "touchleave" : "mouseout" ) + ".gallery3d";\r
-\r
- $( document ).unbind( ".gallery3d" ).bind( "pagechange.gallery3d", function ( e ) {\r
- $( e.target ).find( ".ui-gallery3d" ).gallery3d( "refresh" );\r
- }).bind( "pageremove.gallery3d", function ( e ) {\r
- $( e.target ).find( ".ui-gallery3d" ).trigger( "_destory" );\r
- });\r
-\r
- $( window ).unbind( ".gallery3d" ).bind( "resize.gallery3d orientationchange.gallery3d", function ( e ) {\r
- $( ".ui-page-active" ).find( ".ui-gallery3d" ).gallery3d( "refresh" );\r
- }).bind( "unload.gallery3d", function ( e ) {\r
- $( e.target ).find( ".ui-gallery3d" ).trigger( "_destory" );\r
- });\r
-\r
- view.bind( "_destory", function ( e ) {\r
- self._final();\r
- });\r
-\r
- canvas.bind( "webglcontextlost", function ( e ) {\r
- e.preventDefault();\r
- }).bind( "webglcontextrestored", function ( e ) {\r
- self._init();\r
- }).bind( touchStartEvt, function ( e ) {\r
- var i = 0,\r
- startX = 0,\r
- deltaMaxSteps = 20,\r
- deltas = [ deltaMaxSteps ],\r
- deltaTimes = [ deltaMaxSteps ],\r
- deltaIndex = 0,\r
- dragValue = 0,\r
- dragDirection = false,\r
- prevTime = 0;\r
-\r
- e.preventDefault();\r
- e.stopPropagation();\r
-\r
- if ( self._imageList.length <= 1 ) {\r
- return;\r
- }\r
-\r
- self._stop();\r
-\r
- startX = $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;\r
- prevTime = $.now();\r
-\r
- for ( i = 0; i < deltaMaxSteps; i += 1 ) {\r
- deltas[i] = startX;\r
- deltaTimes[i] = $.now();\r
- }\r
-\r
- deltaIndex += 1;\r
-\r
- view.bind( touchMoveEvt, function ( e ) {\r
- var x, dx, interval;\r
-\r
- e.preventDefault();\r
- e.stopPropagation();\r
-\r
- x = $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;\r
- dx = startX - x;\r
-\r
- deltas[deltaIndex] = x;\r
- deltaTimes[deltaIndex] = $.now();\r
- interval = deltaTimes[deltaIndex] - prevTime;\r
-\r
- deltaIndex = ( deltaIndex + 1 ) % deltaMaxSteps;\r
-\r
- // Validation of drag\r
- if ( Math.abs( dx ) >= 10 && interval >= self._dragInterval ) {\r
- if ( dragDirection !== ( ( dx < 0 ) ? self._DIRECTION_RIGHT : self._DIRECTION_LEFT ) ) {\r
- dragValue = 0;\r
- dragDirection = ( dx < 0 ) ? self._DIRECTION_RIGHT : self._DIRECTION_LEFT;\r
- }\r
-\r
- dragValue += Math.abs( dx ) / 100;\r
- if ( dragValue >= 1 ) {\r
- self._setPosition( self._ANIMATION_END, dragDirection );\r
- dragValue = 0;\r
- } else {\r
- self._setPosition( dragValue, dragDirection );\r
- }\r
- self._drawScene();\r
- startX = x;\r
- prevTime = $.now();\r
- }\r
- }).bind( touchEndEvt, function ( e ) {\r
- var baseTime = 0,\r
- recent = -1,\r
- index = 0,\r
- previous = 0,\r
- baseTimeRatio = 0,\r
- fx = 0,\r
- lastX = 0,\r
- velocityX = 0,\r
- dx = 0,\r
- isSwipe = true,\r
- direction;\r
-\r
- e.preventDefault();\r
- e.stopPropagation();\r
-\r
- // Validation of swipe\r
- baseTime = $.now() - self._swipeThresholdOfBasetimeGap;\r
- lastX = $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;\r
- dx = startX - lastX;\r
- startX = 0;\r
- for ( i = 0; i < deltaMaxSteps; i += 1 ) {\r
- index = ( deltaIndex + i ) % deltaMaxSteps;\r
- if ( deltaTimes[index] > baseTime ) {\r
- recent = index;\r
- break;\r
- }\r
- }\r
- if ( recent < 0 ) {\r
- isSwipe = false;\r
- }\r
-\r
- if ( isSwipe ) {\r
- previous = recent;\r
- for ( i = 0; i < deltaMaxSteps; i += 1 ) {\r
- previous = ( previous - 1 + deltaMaxSteps ) % deltaMaxSteps;\r
- if ( deltaTimes[previous] < deltaTimes[recent] ) {\r
- break;\r
- }\r
- }\r
- // too slow or too fast\r
- if ( i === deltaMaxSteps || baseTime < deltaTimes[previous] ) {\r
- isSwipe = false;\r
- }\r
- }\r
-\r
- if ( isSwipe ) {\r
- baseTimeRatio = ( baseTime - deltaTimes[previous] ) / ( deltaTimes[recent] - deltaTimes[previous] );\r
- fx = ( 1.0 - baseTimeRatio ) * deltas[previous] + baseTimeRatio * deltas[recent];\r
- if ( Math.abs( fx - lastX ) < self._swipeThresholdOfSensitivity ) {\r
- fx = lastX;\r
- }\r
- velocityX = parseInt( ( lastX - fx ) / ( $.now() - baseTime ), 10 );\r
- }\r
-\r
- if ( isSwipe && velocityX ) {\r
- direction = ( velocityX < 0 ) ? self._DIRECTION_LEFT : self._DIRECTION_RIGHT;\r
- self._run( direction, Math.abs( velocityX ), dragValue );\r
- } else if ( dragDirection !== 0 && dragValue ) {\r
- self._animate( null, self._DURATION_DEFAULT * ( 1 - dragValue ), dragDirection, 0, dragValue );\r
- }\r
-\r
- view.unbind( ".gallery3d" );\r
- }).bind( touchLeaveEvt, function ( e ) {\r
- view.trigger( touchEndEvt );\r
- });\r
- });\r
- },\r
-\r
- // ----------------------------------------------------------\r
- // Data parsing\r
- // ----------------------------------------------------------\r
- _loadData: function ( jsonUrl, key ) {\r
- var self = this;\r
-\r
- $.ajax({\r
- async : false,\r
- url : jsonUrl,\r
- dataType: "json",\r
- success : function ( data ) {\r
- self._imageList = $.extend( [], data[ key ] );\r
- }\r
- });\r
- },\r
-\r
- // ----------------------------------------------------------\r
- // WebGL\r
- // ----------------------------------------------------------\r
- _initGL: function ( canvas ) {\r
- var self = this,\r
- gl;\r
-\r
- gl = getContext3D( canvas );\r
- if ( !gl ) {\r
- window.alert( "There's no WebGL context available!!!" );\r
- return null;\r
- }\r
-\r
- gl.enable( gl.BLEND );\r
- gl.blendFunc( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA );\r
-\r
- gl.enable( gl.DEPTH_TEST );\r
- gl.depthFunc( gl.LEQUAL );\r
-\r
- canvas.width = self._VIEWPORT_WIDTH;\r
- canvas.height = self._VIEWPORT_HEIGHT;\r
- gl.viewportWidth = canvas.width;\r
- gl.viewportHeight = canvas.height;\r
- gl.viewport( 0, 0, gl.viewportWidth, gl.viewportHeight );\r
- self._pMatrix = mat4.create();\r
- mat4.perspective( 40, gl.viewportWidth / gl.viewportHeight, 0.1, 10000.0, self._pMatrix );\r
-\r
- gl.clearColor( 0.0, 0.0, 0.0, 1.0 );\r
- gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );\r
-\r
- return gl;\r
- },\r
-\r
- _initShader : function ( gl ) {\r
- var self = this,\r
- shaderProgram;\r
-\r
- shaderProgram = $.webgl.shader.addShaderProgram( self._gl, VERTEX_SHADER, FRAGMENT_SHADER );\r
- gl.useProgram( shaderProgram );\r
-\r
- shaderProgram.vertexPositionAttr = gl.getAttribLocation( shaderProgram, "aVertexPosition" );\r
- gl.enableVertexAttribArray( shaderProgram.vertexPositionAttr );\r
-\r
- shaderProgram.textureCoordAttr = gl.getAttribLocation( shaderProgram, "aTextureCoord" );\r
- gl.enableVertexAttribArray( shaderProgram.textureCoordAttr );\r
-\r
- // Set light normal vectors for lighting~\r
- shaderProgram.vertexNormalAttr = gl.getAttribLocation( shaderProgram, "aVertexNormal" );\r
- gl.enableVertexAttribArray( shaderProgram.vertexNormalAttr );\r
-\r
- shaderProgram.perspectiveMU = gl.getUniformLocation( shaderProgram, "uPerspectiveMatrix");\r
- shaderProgram.transformMU = gl.getUniformLocation( shaderProgram, "uMoveMatrix");\r
- shaderProgram.sampleUniform = gl.getUniformLocation( shaderProgram, "uSampler");\r
-\r
- // Set light variables~\r
- shaderProgram.normalMU = gl.getUniformLocation( shaderProgram, "nNormalMatrix");\r
- shaderProgram.ambientColorU = gl.getUniformLocation( shaderProgram, "uAmbientColor");\r
- shaderProgram.lightDirU_first = gl.getUniformLocation( shaderProgram, "uLightDirection_first");\r
- shaderProgram.lightDirU_second = gl.getUniformLocation( shaderProgram, "uLightDirection_second");\r
- shaderProgram.directionColorU = gl.getUniformLocation( shaderProgram, "uDirectionColor");\r
-\r
- return shaderProgram;\r
- },\r
-\r
- _initBuffers: function ( gl, shaderProgram ) {\r
- var self = this,\r
- i = 0,\r
- mashBase = 0,\r
- vertices = [],\r
- textureCoords = [],\r
- normalVectors = [],\r
- nodes = [],\r
- maxDrawLength = self._MAX_ITEM_COUNT;\r
-\r
- for ( i = 0; i < self._imageList.length + 1; i += 1 ) {\r
- nodes[i] = new Node();\r
- $.merge( vertices, nodes[i].vertices );\r
- $.merge( textureCoords, nodes[i].textureCoords );\r
- $.merge( normalVectors, nodes[i].normalVectors );\r
-\r
- nodes[i].textureBuffer = gl.createBuffer();\r
- gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, nodes[i].textureBuffer );\r
- mashBase = i * 4;\r
- nodes[i].meshOrder = [\r
- mashBase, mashBase + 1, mashBase + 2,\r
- mashBase + 2, mashBase + 3, mashBase\r
- ];\r
- gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new GlArray16( nodes[i].meshOrder ), gl.STATIC_DRAW );\r
- gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); // release buffer memory\r
- nodes[i].textureBufferItemSize = 6;\r
- }\r
-\r
- self._positionBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( vertices ) );\r
- self._positionBuffer.itemSize = 3;\r
-\r
- self._textureCoordBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( textureCoords ) );\r
- self._textureCoordBuffer.itemSize = 2;\r
-\r
- self._normalVectorBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( normalVectors ) ); // Vertex's normal vector for Direction light\r
- self._normalVectorBuffer.itemSize = 3;\r
-\r
- // Ambient light\r
- gl.uniform3f( shaderProgram.ambientColorU, 0.1, 0.1, 0.1 );\r
- // Direcntion light\r
- gl.uniform3f( shaderProgram.directionColorU, 1.0, 1.0, 1.0 );\r
-\r
- return nodes;\r
- },\r
-\r
- // ----------------------------------------------------------\r
- // Texture\r
- // ----------------------------------------------------------\r
- _initTextures: function ( gl, nodes ) {\r
- var self = this;\r
-\r
- $( nodes ).each( function ( i ) {\r
- var node = nodes[i],\r
- url;\r
-\r
- if ( !self._imageList[i] ) {\r
- return false;\r
- }\r
-\r
- url = self._imageList[i].src;\r
- node.texture = gl.createTexture();\r
- self._loadImage( url, i, i, gl, nodes );\r
- });\r
- },\r
-\r
- _loadImage: function ( url, i, imageID, gl, nodes ) {\r
- var self = this,\r
- isMipmap = false,\r
- image,\r
- node;\r
-\r
- gl = gl || self._gl;\r
- nodes = nodes || self._nodes;\r
- isMipmap = isMipmap || false;\r
- node = nodes[i];\r
- node.image = node.image || new Image();\r
-\r
- $( node.image ).one( "load", function ( e ) {\r
- self._bindTexture( gl, node, this, isMipmap );\r
- node.imageID = imageID;\r
-\r
- if ( !self._animationID ) {\r
- self._setPosition( 0, 0 );\r
- }\r
- });\r
-\r
- if ( self.options.thumbnailCache ) {\r
- $.imageloader.getThumbnail( url, function ( result ) {\r
- if ( result === "NOT_FOUND_ERR" ) {\r
- $.imageloader.setThumbnail( url, function ( result ) {\r
- if ( result && result.length > 30 ) {\r
- node.image.src = result;\r
- isMipmap = true;\r
- } else {\r
- node.image.src = url;\r
- }\r
- });\r
- } else if ( result && result.length > 30 ) {\r
- node.image.src = result;\r
- isMipmap = true;\r
- } else {\r
- node.image.src = url;\r
- }\r
- });\r
- } else {\r
- node.image.src = url;\r
- }\r
- },\r
-\r
- _bindTexture: function ( gl, node, image, isMipmap ) {\r
- if ( !node || !node.texture ) {\r
- return;\r
- }\r
-\r
- gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true );\r
-\r
- gl.bindTexture( gl.TEXTURE_2D, node.texture );\r
- gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image );\r
-\r
- if ( isMipmap ) {\r
- gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );\r
- gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST );\r
- gl.generateMipmap( gl.TEXTURE_2D );\r
- } else {\r
- gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );\r
- gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR );\r
- }\r
-\r
- gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );\r
- gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );\r
-\r
- node.texture.loaded = true;\r
-\r
- // release texture memory\r
- gl.bindTexture( gl.TEXTURE_2D, null );\r
- },\r
-\r
- // ----------------------------------------------------------\r
- // rendering\r
- // ----------------------------------------------------------\r
- _setPosition: function ( progress, direction ) {\r
- var self = this,\r
- nodes = self._nodes,\r
- imageList = self._imageList,\r
- imageListLength = imageList.length,\r
- itemCount = self._MAX_ITEM_COUNT,\r
- displayLength = ( imageListLength > itemCount ) ? itemCount : imageListLength,\r
- nextLevelLenth = 0,\r
- i = 0,\r
- t = 0,\r
- position = 0,\r
- angle = 0,\r
- current = 0,\r
- next = 0,\r
- nextLevel = 0,\r
- path = self._path,\r
- nextImageID = 0;\r
-\r
- nextLevelLenth = ( direction >= 0 ) ? displayLength + 1 : displayLength;\r
-\r
- if ( !nodes[i].level ) {\r
- nodes[i].level = displayLength;\r
- }\r
-\r
- for ( i = 0; i < displayLength; i += 1 ) {\r
- if ( !nodes[i].mvMatrix ) {\r
- nodes[i].mvMatrix = mat4.create();\r
- }\r
-\r
- if ( direction > 0 && nodes[i].level >= displayLength ) {\r
- nodes[i].level = 0;\r
- }\r
-\r
- current = path.levels[nodes[i].level];\r
- nextLevel = ( nodes[i].level + nextLevelLenth + direction ) % nextLevelLenth;\r
- next = path.levels[nextLevel];\r
-\r
- if ( imageListLength > itemCount ) {\r
- if ( direction > 0 && nextLevel === 1\r
- && self._firstImageNumber !== nodes[i].imageID ) {\r
- self._loadImage( imageList[self._firstImageNumber].src, i, self._firstImageNumber );\r
- } else if ( direction < 0 && nextLevel === nextLevelLenth - 1\r
- && self._lastImageNumber !== nodes[i].imageID ) {\r
- self._loadImage( imageList[self._lastImageNumber].src, i, self._lastImageNumber );\r
- }\r
- }\r
-\r
- mat4.identity( nodes[i].mvMatrix );\r
- mat4.translate( nodes[i].mvMatrix, [-2.0, -2.0, 1.0] );\r
- mat4.rotate( nodes[i].mvMatrix, self._degreeToRadian( 19 ), [1, 0, 0] );\r
-\r
- t = ( current + ( next - current ) * ( ( progress > 1 ) ? 1 : progress ) );\r
-\r
- if ( progress >= self._ANIMATION_END ) {\r
- nodes[i].level = nextLevel || displayLength;\r
- t = path.levels[nodes[i].level];\r
- }\r
-\r
- if ( ( progress < self._ANIMATION_END )\r
- && ( direction <= 0 && nodes[i].level < 1 ) ) {\r
- nodes[i].drawable = false;\r
- } else {\r
- nodes[i].drawable = true;\r
- }\r
-\r
- if ( progress === self._ANIMATION_END && nodes[i].level === 1 ) {\r
- self.element.trigger( "select", imageList[ nodes[i].imageID ], nodes[i].imageID );\r
- }\r
-\r
- position = path.getPosition( t );\r
- angle = path.getAngle( t );\r
-\r
- mat4.translate( nodes[i].mvMatrix, position );\r
- mat4.rotate( nodes[i].mvMatrix, angle, [0, 1, 0] );\r
- }\r
-\r
- if ( imageListLength > itemCount && progress >= self._ANIMATION_END ) {\r
- self._firstImageNumber = ( self._firstImageNumber - direction ) % imageListLength;\r
- if ( self._firstImageNumber < 0 ) {\r
- self._firstImageNumber = imageListLength - 1;\r
- }\r
-\r
- self._lastImageNumber = ( self._lastImageNumber - direction ) % imageListLength;\r
- if ( self._lastImageNumber < 0 ) {\r
- self._lastImageNumber = imageListLength - 1;\r
- }\r
- }\r
- self._drawScene();\r
- },\r
-\r
- _drawScene: function () {\r
- if ( !this._gl || !this._shaderProgram ) {\r
- return;\r
- }\r
-\r
- var self = this,\r
- gl = self._gl,\r
- shaderProgram = self._shaderProgram,\r
- nodes = self._nodes,\r
- nodesLength = nodes.length,\r
- i;\r
-\r
- gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );\r
-\r
- gl.bindBuffer( gl.ARRAY_BUFFER, self._positionBuffer );\r
- gl.vertexAttribPointer( shaderProgram.vertexPositionAttr, self._positionBuffer.itemSize, gl.FLOAT, false, 0, 0 );\r
-\r
- gl.bindBuffer( gl.ARRAY_BUFFER, self._textureCoordBuffer );\r
- gl.vertexAttribPointer( shaderProgram.textureCoordAttr, self._textureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0 );\r
-\r
- gl.bindBuffer( gl.ARRAY_BUFFER, self._normalVectorBuffer );\r
- gl.vertexAttribPointer( shaderProgram.vertexNormalAttr, self._normalVectorBuffer.itemSize, gl.FLOAT, false, 0, 0 );\r
-\r
- for ( i = 0; i < nodesLength; i += 1 ) {\r
- if ( nodes[i].drawable ) {\r
- self._drawElement( self._pMatrix, nodes[i] );\r
- }\r
- }\r
- },\r
-\r
- _drawElement: function ( perspectiveMatrix, targetNode ) {\r
- var self = this,\r
- gl = self._gl,\r
- shaderProgram = self._shaderProgram,\r
- moveMatrix = targetNode.mvMatrix,\r
- texture = targetNode.texture,\r
- meshIndexBuffer = targetNode.textureBuffer,\r
- meshIndexBufferItemSize = targetNode.textureBufferItemSize,\r
- lightPositions = self._lightsPositionStack,\r
- LightDir,\r
- normalMatrix;\r
-\r
- if ( !moveMatrix ) {\r
- return;\r
- }\r
-\r
- gl.activeTexture( gl.TEXTURE0 );\r
- if ( texture && texture.loaded ) {\r
- gl.bindTexture( gl.TEXTURE_2D, texture );\r
- }\r
- gl.uniform1i( shaderProgram.sampleUniform, 0 );\r
-\r
- LightDir = vec3.create();\r
- vec3.normalize( lightPositions[0], LightDir );\r
- vec3.scale( LightDir, -8 );\r
- gl.uniform3fv( shaderProgram.lightDirU_first, LightDir );\r
-\r
- vec3.normalize( lightPositions[1], LightDir );\r
- vec3.scale( LightDir, -1 );\r
- gl.uniform3fv( shaderProgram.lightDirU_second, LightDir );\r
- gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, meshIndexBuffer );\r
-\r
- gl.uniformMatrix4fv( shaderProgram.perspectiveMU, false, perspectiveMatrix );\r
- gl.uniformMatrix4fv( shaderProgram.transformMU, false, moveMatrix );\r
-\r
- normalMatrix = mat3.create();\r
- mat4.toInverseMat3( moveMatrix, normalMatrix );\r
- mat3.transpose( normalMatrix );\r
- gl.uniformMatrix3fv( shaderProgram.normalMU, false, normalMatrix );\r
-\r
- gl.drawElements( gl.TRIANGLES, meshIndexBufferItemSize, gl.UNSIGNED_SHORT, 0 );\r
-\r
- // release buffer memory\r
- gl.bindBuffer( gl.ARRAY_BUFFER, null );\r
- gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );\r
-\r
- // release texture memory\r
- gl.bindTexture( gl.TEXTURE_2D, null );\r
- },\r
-\r
- // ----------------------------------------------------------\r
- // Animation\r
- // ----------------------------------------------------------\r
- _animate: function ( easingType, duration, direction, repeatCount, startValue, _removeCount ) {\r
- var self = this,\r
- timeNow = $.now(),\r
- progress,\r
- removeCount = 0;\r
-\r
- easingType = easingType || "linear";\r
- startValue = startValue || 0;\r
- _removeCount = _removeCount || 0;\r
-\r
- if ( self._sumTime >= duration ) {\r
- self._setPosition( self._ANIMATION_END, direction );\r
- self._stop();\r
- return;\r
- }\r
-\r
- if ( self._startTime === 0 ) {\r
- self._startTime = timeNow;\r
- } else {\r
- self._sumTime = timeNow - self._startTime;\r
- progress = $.easing[ easingType ]( self._sumTime / duration, self._sumTime, startValue, repeatCount + 1, duration );\r
- removeCount = parseInt( Math.abs( progress ), 10 );\r
-\r
- if ( _removeCount !== removeCount ) {\r
- self._setPosition( self._ANIMATION_END, direction );\r
- _removeCount = removeCount;\r
-\r
- if ( ( repeatCount - _removeCount ) >= 0 ) {\r
- self._animate( easingType, duration, direction, repeatCount, startValue, _removeCount );\r
- } else {\r
- self._stop();\r
- }\r
- return;\r
- }\r
-\r
- self._setPosition( progress - _removeCount, direction );\r
- }\r
-\r
- self._animationID = window.requestAnimationFrame( function () {\r
- self._animate( easingType, duration, direction, repeatCount, startValue, _removeCount );\r
- });\r
- },\r
-\r
- _run: function ( direction, repeatCount, startValue ) {\r
- var self = this,\r
- repeat = repeatCount || 0,\r
- duration = self._DURATION_DEFAULT * ( repeat + 1 );\r
-\r
- if ( self._imageList.length <= 1 ) {\r
- return;\r
- }\r
-\r
- startValue = startValue || 0;\r
- duration = ( duration >= 0 ) ? duration : 0;\r
-\r
- if ( self._animationID ) {\r
- self._setPosition( self._ANIMATION_END, direction );\r
- self._stop();\r
- }\r
-\r
- self._animate( "easeOutExpo", duration, direction, repeat, startValue );\r
- },\r
-\r
- _reset: function () {\r
- if ( !this._canvas || !this._gl ) {\r
- return;\r
- }\r
-\r
- this._final();\r
- this._init();\r
- this.refresh();\r
- },\r
-\r
- _stop: function () {\r
- if ( this._animationID ) {\r
- window.cancelAnimationFrame( this._animationID );\r
- }\r
- this._animationID = 0;\r
-\r
- this._startTime = 0;\r
- this._sumTime = 0;\r
- },\r
-\r
- _degreeToRadian: function ( degree ) {\r
- return degree * Math.PI / 180;\r
- },\r
-\r
- next: function () {\r
- this._run( this._DIRECTION_LEFT , 0 );\r
- },\r
-\r
- prev: function () {\r
- this._run( this._DIRECTION_RIGHT, 0 );\r
- },\r
-\r
- refresh: function () {\r
- var view = this.element,\r
- canvas = view.find( "canvas.ui-gallery3d-canvas" );\r
-\r
- if ( canvas.width() !== view.width() ) {\r
- canvas.width( view.width() );\r
- }\r
-\r
- if ( !this._animationID ) {\r
- this._setPosition( 0, 0 );\r
- }\r
- },\r
-\r
- select: function ( index ) {\r
- var nodes = this._nodes,\r
- repeat,\r
- i,\r
- imageID,\r
- object = null,\r
- target = 0,\r
- direction = 0;\r
-\r
- if ( index && this._animationID ) {\r
- this._stop();\r
- }\r
-\r
- for ( i in nodes ) {\r
- if ( nodes[i].level === 1 ) {\r
- object = this._imageList[ nodes[i].imageID ];\r
- imageID = nodes[i].imageID;\r
- break;\r
- }\r
- }\r
-\r
- if ( !index ) {\r
- return object;\r
- }\r
-\r
- if ( index < 0 && index >= this._imageList.length ) {\r
- return;\r
- }\r
-\r
- target = index - imageID;\r
- direction = ( target > 0 ) ? this._DIRECTION_LEFT\r
- : ( ( target < 0 ) ? this._DIRECTION_RIGHT : 0 );\r
- if ( direction ) {\r
- this._run( direction, Math.abs( target ) - 1 );\r
- }\r
- },\r
-\r
- add: function ( item, index ) {\r
- if ( !item ) {\r
- return;\r
- }\r
-\r
- if ( typeof item === "string" ) {\r
- item = { "src" : item };\r
- }\r
-\r
- index = index || 0;\r
- if ( typeof index !== "number" && index < 0\r
- && index >= this._imageList.length ) {\r
- return;\r
- }\r
-\r
- this._imageList.splice( index, 0, item );\r
- if ( this._gl ) {\r
- this._reset();\r
- }\r
- },\r
-\r
- remove: function ( index ) {\r
- index = index || 0;\r
- if ( typeof index !== "number" && index < 0\r
- && index >= this._imageList.length ) {\r
- return;\r
- }\r
-\r
- this._imageList.splice( index, 1 );\r
- if ( this._gl ) {\r
- this._reset();\r
- }\r
- },\r
-\r
- clearThumbnailCache: function () {\r
- if ( !this._nodes || ( this._nodes.length <= 0 ) ) {\r
- return;\r
- }\r
-\r
- var i, url;\r
- for ( i = 0; i < this._imageList.length; i += 1 ) {\r
- url = this._imageList[i].src;\r
- $.imageloader.removeThumbnail( url );\r
- }\r
- },\r
-\r
- empty: function () {\r
- this._imageList = [];\r
- this._reset();\r
- },\r
-\r
- length: function () {\r
- return this._imageList.length;\r
- }\r
- });\r
-\r
- $( document ).bind( "pagecreate create", function ( e ) {\r
- $( ":jqmData(role='gallery3d')" ).gallery3d();\r
- });\r
-\r
-} ( jQuery, document, window ) );\r
-\r
-//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);\r
-} );\r
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+//>>description: 3D photo gallery widget.
+//>>label: Gallery3d
+//>>group: Tizen:Widgets
+
+define( [ "components/imageloader", "components/motionpath", "components/webgl" ], function ( ) {
+//>>excludeEnd("jqmBuildExclude");
+
+
+/* ***************************************************************************
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * ***************************************************************************
+ *
+ * Authors: Hyunsook Park <hyunsook.park@samsung.com>
+ * Wonseop Kim <wonseop.kim@samsung.com>
+ */
+
+/**
+ * The gallery3d widget displays images along a curved path on a 3-dimensional coordinate system.
+ * To improve performance, the size of image(s) displayed on the screen should be a square(under
+ * 128X128 pixel) as possible. But if a user can't resize the images, this widget supports an image
+ * resizing feature and he/she can use it with "data-thumbnail-cache" option. ("data-thumbnail-cache"
+ * option resizes the gallery images under 128x128 pixels and stores the images on a local storage.
+ * So when a gallery3D widget is re-launched, the widget reuse the storage and a user can improve
+ * launching time. A browser or web runtime engine should support "Web Storage" feature to use that
+ * option.)
+ *
+ * HTML Attributes:
+ *
+ * data-thumbnail-cache : Determines whether to cache and resize images.
+ *
+ * APIs:
+ *
+ * next ( void )
+ * : This method moves each image forward one by one.
+ * prev ( void )
+ * : This method moves each image backward one by one.
+ * select ( [number] )
+ * : When the "select" method is called with an argument, the method selects the image of given index.
+ * If the method is called with no argument, it will return the Javascript object having "src"
+ * attribute having the selected image’s URL.
+ * add ( object or string [, number] )
+ * This method adds an image to Gallery3D widget.
+ * If the second argument isn't inputted, the image is added at the 0th position.
+ * remove ( [number] )
+ * : This method deletes an image from Gallery3d widget.
+ * The argument defines the index of the image to be deleted.
+ * If an argument isn't inputted, it removes current image.
+ * clearThumbnailCache ( void )
+ * : This method clears the cache data of all images when thumbnailCache option is set as 'true'.
+ * refresh ( void )
+ * : This method updates and redraws current widget.
+ * empty ( void )
+ * : This method removes all of images from Gallery3D widget.
+ * length ( void )
+ * : This method gets the number of images.
+ *
+ * Events:
+ *
+ * select : Triggered when an image is selected.
+ *
+ * Examples:
+ *
+ * <script>
+ * $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ * $( "#gallery3d" ).gallery3d( "add", "01.jpg" );
+ * });
+ * </script>
+ * <div id="gallery3d" data-role="gallery3d"></div>
+ */
+
+/**
+ @class Gallery3D
+ The gallery3d widget displays images along a curved path on a 3-dimensional coordinate system.
+ <br/><br/>To add an gallery3d widget to the application, use the following code:
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", "01.jpg" );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @property {Boolean} data-thumbnail-cache
+ Determines whether to cache and resize images.
+ To improve performance, the size of image(s) displayed on the screen should be a square (under 128X128 pixels).
+ "data-thumbnail-cache" option resizes the gallery images under 128x128 pixels and stores the images on a local storage.
+ So when a gallery3D widget is re-launched, the widget reuses the storage and the launching time can be improved.
+ A browser or web runtime engine must support "Web Storage" feature to use this option.
+*/
+/**
+ @event select
+ Triggered when an image is selected.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } );
+ }).on( "select", function ( event, data, index ) {
+ // Handle the select event
+ var urlOfImage = data.src, indexOfImage = index;
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method next
+ This method moves each image forward one by one.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } )
+ .gallery3d( "next" );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method prev
+ This method moves each image backward one by one.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } )
+ .gallery3d( "prev" );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method select
+ When the "select" method is called with an argument, the method selects the image of given index.
+ If the method is called with no argument, it will return the Javascript object having "src" attribute having the selected image’s URL.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } );
+ var selectedImage = $("#gallery3d"). gallery3d( "select" );
+ // selectedImage = { src: "3.jpg" };
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method add
+ This method adds an image to Gallery3D widget.
+ The first argument is a Javascript object having a "src" attribute or a string of image's path.
+ The second argument is an index of images.
+ If second argument isn't inputted, the image is added at the 0th position.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", "2.jpg", 1 );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method remove
+ This method deletes an image from Gallery3d widget.
+ The argument defines the index of the image to be deleted.
+ If an argument isn't inputted, it removes current image.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } );
+
+ $( "#gallery3d" ).gallery3d( "remove" );
+ $( "#gallery3d" ).gallery3d( "remove", 1 );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method clearThumbnailCache
+ This method clears the cache data of all images when thumbnailCache option is set as 'true'
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } );
+
+ $( "#gallery3d" ).gallery3d( "clearThumbnailCache" );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d" data-thumbnail-cache="true"></div>
+*/
+/**
+ @method refresh
+ This method updates and redraws current widget.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } );
+
+ $( "#gallery3d" ).gallery3d( "refresh" );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method empty
+ This method removes all of images from Gallery3D widget.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } );
+
+ $( "#gallery3d" ).gallery3d( "empty" );
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+/**
+ @method length
+ This method gets the number of images.
+
+ <script>
+ $( "#gallery3d" ).on( "gallery3dcreate", function () {
+ $( "#gallery3d" ).gallery3d( "add", { src: "1.jpg" } )
+ .gallery3d( "add", { src: "2.jpg" } )
+ .gallery3d( "add", { src: "3.jpg" } );
+
+ var imagesLength = $( "#gallery3d" ).gallery3d( "length" );
+ // imagesLength = 3;
+ });
+ </script>
+ <div id="gallery3d" data-role="gallery3d"></div>
+*/
+
+( function ( $, document, window, undefined ) {
+ window.requestAnimationFrame = ( function () {
+ return function ( callback ) {
+ var id = window.setTimeout( callback, 1000 / 60 );
+ return id;
+ };
+ } () );
+
+ window.cancelAnimationFrame = ( function () {
+ return function ( id ) {
+ window.clearTimeout( id );
+ };
+ } () );
+
+ var vec3 = window.vec3,
+ mat3 = window.mat3,
+ mat4 = window.mat4,
+ GlArray32 = ( typeof window.Float32Array !== "undefined" ? window.Float32Array : ( typeof window.WebGLFloatArray !== "undefined" ? window.WebGLFloatArray : Array ) ),
+ GlArray16 = ( typeof window.Uint16Array !== "undefined" ? window.Uint16Array : Array ),
+ getContext3D = function ( canvas ) {
+ var gl, i,
+ contextNames = [ "experimental-webgl", "webkit-3d", "webgl", "moz-webgl" ];
+
+ for ( i = 0; i < contextNames.length; i += 1 ) {
+ try {
+ gl = canvas.getContext( contextNames[i] );
+ if ( gl ) {
+ break;
+ }
+ } catch ( e ) {
+ window.alert( "Unfortunately, there's a WebGL compatibility problem. </br> You may want to check your system settings." );
+ return;
+ }
+ }
+ return gl;
+ },
+ VERTEX_SHADER = [
+ "attribute vec3 aVertexPosition;",
+ "attribute vec2 aTextureCoord;",
+ "attribute vec3 aVertexNormal;",
+ "uniform mat4 uMoveMatrix;",
+ "uniform mat4 uPerspectiveMatrix;",
+ "uniform mat3 nNormalMatrix;",
+ "uniform vec3 uAmbientColor;",
+ "uniform vec3 uLightDirection;",
+ "uniform vec3 uDirectionColor;",
+ "uniform vec3 uLightDirection_first;",
+ "uniform vec3 uLightDirection_second;",
+ "varying vec2 vTextureCoord;",
+ "varying vec3 vLightWeight;",
+ "varying vec4 vFogWeight;",
+
+ "void main(void) {",
+ " vec4 v_Position = uMoveMatrix * vec4(aVertexPosition, 1.0);",
+ " gl_Position = uPerspectiveMatrix * v_Position;",
+ " vTextureCoord = aTextureCoord;",
+ " float fog = 1.0 - ((gl_Position.z + 1.5) / 60.0);",
+ " vFogWeight = clamp( vec4( fog, fog, fog, 1.0), 0.6, 1.0);",
+ " vec3 transNormalVector = nNormalMatrix * aVertexNormal;",
+
+ " float vLightWeightFirst = 0.0;",
+ " float vLightWeightSecond = max( dot(transNormalVector, uLightDirection_second), 0.0 );",
+
+ " vLightWeight = uAmbientColor + uDirectionColor * vLightWeightSecond;",
+ "}"
+ ].join( "\n" ),
+ FRAGMENT_SHADER = [
+ "precision mediump float;",
+ "varying vec2 vTextureCoord;",
+ "varying vec3 vLightWeight;",
+ "uniform sampler2D uSampler;",
+ "varying vec4 vFogWeight;",
+
+ "void main(void) {",
+ " vec4 TextureColor;",
+ " if ( vTextureCoord.s <= 0.01 || vTextureCoord.s >= 0.99 || vTextureCoord.t <= 0.01 || vTextureCoord.t >= 0.99 ) {",
+ " TextureColor = vec4(1.0, 1.0, 1.0, 0.5);",
+ " } else {",
+ " TextureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));",
+ " }",
+ " TextureColor *= vFogWeight;",
+ " gl_FragColor = vec4(TextureColor.rgb * vLightWeight, TextureColor.a);",
+ "}"
+ ].join( "\n" );
+
+ function Node() {
+ this.vertices = [
+ -1.0, -1.0, 0.0,
+ 1.0, -1.0, 0.0,
+ 1.0, 1.0, 0.0,
+ -1.0, 1.0, 0.0
+ ];
+ this.textureCoords = [
+ 1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0
+ ];
+ this.normalVectors = [
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0
+ ];
+ this.texture = null;
+ this.textureBuffer = null;
+ this.textureBufferItemSize = 0;
+ this.mashOrder = [];
+ this.mvMatrix = null;
+ this.level = -1;
+ this.targetLevel = 0;
+ this.drawable = false;
+ this.image = null;
+ this.imageID = 0;
+ }
+
+ $.widget( "tizen.gallery3d", $.mobile.widget, {
+ options: {
+ thumbnailCache: false
+ },
+
+ _MAX_ITEM_COUNT: 28,
+ _ANIMATION_END: 999,
+ _DURATION_DEFAULT: 300,
+ _DURATION_FIRST: 1600,
+ _VIEWPORT_WIDTH: 1024,
+ _VIEWPORT_HEIGHT: 456,
+ _DIRECTION_LEFT: -1,
+ _DIRECTION_RIGHT: +1,
+
+ _gl: null,
+ _shaderProgram : null,
+ _positionBuffer : null,
+ _textureCoordBuffer : null,
+ _normalVectorBuffer : null,
+ _nodes: null,
+ _pMatrix : null,
+ _animationID: 0,
+ _dragInterval : 0,
+ _startTime : 0,
+ _sumTime : 0,
+ _lightsPositionStack : [
+ [0.0, 0.0, -1.0], // back
+ [-0.2, 0.0, 0.7] // front
+ ],
+ _path: null,
+ _swipeThresholdOfBasetimeGap: ( $.support.touch ? 30 : 70 ),
+ _swipeThresholdOfSensitivity: ( $.support.touch ? 2.0 : 10.0 ),
+ _canvas: null,
+ _imageList: [],
+ _maxDrawLength: 0,
+ _firstImageNumber: 0,
+ _lastImageNumber: 0,
+
+ _create: function () {
+ var self = this,
+ view = self.element,
+ option = self.options;
+
+ self._canvas = $( "<canvas class='ui-gallery3d-canvas'></canvas>" );
+
+ view.addClass( "ui-gallery3d" ).append( self._canvas );
+ self._addBehavier();
+
+ self._dragInterval = 1000 / 30; // 30fps
+
+ $.each( self.options, function ( key, value ) {
+ self.options[ key ] = undefined;
+ self._setOption( key, value );
+ });
+
+ },
+
+ _setOption: function ( key, value ) {
+ switch ( key ) {
+ case "thumbnailCache" :
+ if ( typeof value === "string" ) {
+ value = ( value === "true" ) ? true : false;
+ } else {
+ value = !!value;
+ }
+ this._reset();
+ break;
+ }
+
+ $.mobile.widget.prototype._setOption.call( this, key, value );
+ },
+
+ _init: function ( canvas ) {
+ var self = this,
+ pathPoints = [
+ [40, 0, -48],
+ [-12, 0, -40], // contorl Point of Point1
+ [24, 0, -9], // contorl Point of Point2
+ [-5, 0, -5]
+ ],
+ i;
+
+ canvas = canvas || self._canvas;
+
+ if ( !canvas ) {
+ return;
+ }
+
+ self._gl = self._gl || self._initGL( canvas[0] );
+ if ( !self._gl ) {
+ return;
+ }
+
+ if ( !self._imageList ) {
+ return;
+ }
+
+ self._shaderProgram = self._shaderProgram || self._initShader( self._gl );
+ if ( !self._shaderProgram ) {
+ return;
+ }
+
+ if ( self._imageList.length > self._MAX_ITEM_COUNT ) {
+ self._firstImageNumber = self._imageList.length - 1;
+ self._lastImageNumber = self._MAX_ITEM_COUNT - 1;
+ }
+
+ self._nodes = self._initBuffers( self._gl, self._shaderProgram );
+
+ self._initTextures( self._gl, self._nodes );
+
+ self._path = $.motionpath( "bezier2d", {
+ points: pathPoints,
+ maxLevel: self._MAX_ITEM_COUNT
+ } );
+ for ( i = 0; i < self._nodes.length; i += 1 ) {
+ self._path.levels[i] = self._path.levels[i + 1] || 0;
+ self._nodes[i].level = i;
+ }
+ },
+
+ _final: function ( canvas ) {
+ var self = this,
+ gl = self._gl;
+
+ if ( !gl ) {
+ return;
+ }
+
+ canvas = canvas || self._canvas;
+
+ $( self._nodes ).each( function ( i ) {
+ var node = self._nodes[i];
+ gl.deleteTexture( node.texture );
+ node.texture = null;
+ });
+ self._nodes = null;
+
+ gl.deleteBuffer( self._positionBuffer );
+ self._positionBuffer = null;
+ gl.deleteBuffer( self._textureCoordBuffer );
+ self._textureCoordBuffer = null;
+ gl.deleteBuffer( self._normalVectorBuffer );
+ self._normalVectorBuffer = null;
+
+ $.webgl.shader.deleteShaders( gl );
+ gl.deleteProgram( self._shaderProgram );
+ self._shaderProgram = null;
+
+ self._gl = gl = null;
+ },
+
+ _addBehavier : function () {
+ var self = this,
+ view = self.element,
+ canvas = self._canvas,
+ touchStartEvt = ( $.support.touch ? "touchstart" : "mousedown" ),
+ touchMoveEvt = ( $.support.touch ? "touchmove" : "mousemove" ) + ".gallery3d",
+ touchEndEvt = ( $.support.touch ? "touchend" : "mouseup" ) + ".gallery3d",
+ touchLeaveEvt = ( $.support.touch ? "touchleave" : "mouseout" ) + ".gallery3d";
+
+ $( document ).unbind( ".gallery3d" ).bind( "pagechange.gallery3d", function ( e ) {
+ $( e.target ).find( ".ui-gallery3d" ).gallery3d( "refresh" );
+ }).bind( "pageremove.gallery3d", function ( e ) {
+ $( e.target ).find( ".ui-gallery3d" ).trigger( "_destory" );
+ });
+
+ $( window ).unbind( ".gallery3d" ).bind( "resize.gallery3d orientationchange.gallery3d", function ( e ) {
+ $( ".ui-page-active" ).find( ".ui-gallery3d" ).gallery3d( "refresh" );
+ }).bind( "unload.gallery3d", function ( e ) {
+ $( e.target ).find( ".ui-gallery3d" ).trigger( "_destory" );
+ });
+
+ view.bind( "_destory", function ( e ) {
+ self._final();
+ });
+
+ canvas.bind( "webglcontextlost", function ( e ) {
+ e.preventDefault();
+ }).bind( "webglcontextrestored", function ( e ) {
+ self._init();
+ }).bind( touchStartEvt, function ( e ) {
+ var i = 0,
+ startX = 0,
+ deltaMaxSteps = 20,
+ deltas = [ deltaMaxSteps ],
+ deltaTimes = [ deltaMaxSteps ],
+ deltaIndex = 0,
+ dragValue = 0,
+ dragDirection = false,
+ prevTime = 0;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ if ( self._imageList.length <= 1 ) {
+ return;
+ }
+
+ self._stop();
+
+ startX = $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;
+ prevTime = $.now();
+
+ for ( i = 0; i < deltaMaxSteps; i += 1 ) {
+ deltas[i] = startX;
+ deltaTimes[i] = $.now();
+ }
+
+ deltaIndex += 1;
+
+ view.bind( touchMoveEvt, function ( e ) {
+ var x, dx, interval;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ x = $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;
+ dx = startX - x;
+
+ deltas[deltaIndex] = x;
+ deltaTimes[deltaIndex] = $.now();
+ interval = deltaTimes[deltaIndex] - prevTime;
+
+ deltaIndex = ( deltaIndex + 1 ) % deltaMaxSteps;
+
+ // Validation of drag
+ if ( Math.abs( dx ) >= 10 && interval >= self._dragInterval ) {
+ if ( dragDirection !== ( ( dx < 0 ) ? self._DIRECTION_RIGHT : self._DIRECTION_LEFT ) ) {
+ dragValue = 0;
+ dragDirection = ( dx < 0 ) ? self._DIRECTION_RIGHT : self._DIRECTION_LEFT;
+ }
+
+ dragValue += Math.abs( dx ) / 100;
+ if ( dragValue >= 1 ) {
+ self._setPosition( self._ANIMATION_END, dragDirection );
+ dragValue = 0;
+ } else {
+ self._setPosition( dragValue, dragDirection );
+ }
+ self._drawScene();
+ startX = x;
+ prevTime = $.now();
+ }
+ }).bind( touchEndEvt, function ( e ) {
+ var baseTime = 0,
+ recent = -1,
+ index = 0,
+ previous = 0,
+ baseTimeRatio = 0,
+ fx = 0,
+ lastX = 0,
+ velocityX = 0,
+ dx = 0,
+ isSwipe = true,
+ direction;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ // Validation of swipe
+ baseTime = $.now() - self._swipeThresholdOfBasetimeGap;
+ lastX = $.support.touch ? e.originalEvent.changedTouches[0].pageX : e.pageX;
+ dx = startX - lastX;
+ startX = 0;
+ for ( i = 0; i < deltaMaxSteps; i += 1 ) {
+ index = ( deltaIndex + i ) % deltaMaxSteps;
+ if ( deltaTimes[index] > baseTime ) {
+ recent = index;
+ break;
+ }
+ }
+ if ( recent < 0 ) {
+ isSwipe = false;
+ }
+
+ if ( isSwipe ) {
+ previous = recent;
+ for ( i = 0; i < deltaMaxSteps; i += 1 ) {
+ previous = ( previous - 1 + deltaMaxSteps ) % deltaMaxSteps;
+ if ( deltaTimes[previous] < deltaTimes[recent] ) {
+ break;
+ }
+ }
+ // too slow or too fast
+ if ( i === deltaMaxSteps || baseTime < deltaTimes[previous] ) {
+ isSwipe = false;
+ }
+ }
+
+ if ( isSwipe ) {
+ baseTimeRatio = ( baseTime - deltaTimes[previous] ) / ( deltaTimes[recent] - deltaTimes[previous] );
+ fx = ( 1.0 - baseTimeRatio ) * deltas[previous] + baseTimeRatio * deltas[recent];
+ if ( Math.abs( fx - lastX ) < self._swipeThresholdOfSensitivity ) {
+ fx = lastX;
+ }
+ velocityX = parseInt( ( lastX - fx ) / ( $.now() - baseTime ), 10 );
+ }
+
+ if ( isSwipe && velocityX ) {
+ direction = ( velocityX < 0 ) ? self._DIRECTION_LEFT : self._DIRECTION_RIGHT;
+ self._run( direction, Math.abs( velocityX ), dragValue );
+ } else if ( dragDirection !== 0 && dragValue ) {
+ self._animate( null, self._DURATION_DEFAULT * ( 1 - dragValue ), dragDirection, 0, dragValue );
+ }
+
+ view.unbind( ".gallery3d" );
+ }).bind( touchLeaveEvt, function ( e ) {
+ view.trigger( touchEndEvt );
+ });
+ });
+ },
+
+ // ----------------------------------------------------------
+ // WebGL
+ // ----------------------------------------------------------
+ _initGL: function ( canvas ) {
+ var self = this,
+ gl;
+
+ gl = getContext3D( canvas );
+ if ( !gl ) {
+ window.alert( "There's no WebGL context available!!!" );
+ return null;
+ }
+
+ gl.enable( gl.BLEND );
+ gl.blendFunc( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
+
+ gl.enable( gl.DEPTH_TEST );
+ gl.depthFunc( gl.LEQUAL );
+
+ canvas.width = self._VIEWPORT_WIDTH;
+ canvas.height = self._VIEWPORT_HEIGHT;
+ gl.viewportWidth = canvas.width;
+ gl.viewportHeight = canvas.height;
+ gl.viewport( 0, 0, gl.viewportWidth, gl.viewportHeight );
+ self._pMatrix = mat4.create();
+ mat4.perspective( 40, gl.viewportWidth / gl.viewportHeight, 0.1, 10000.0, self._pMatrix );
+
+ gl.clearColor( 0.15, 0.15, 0.15, 1.0 );
+ gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
+
+ return gl;
+ },
+
+ _initShader : function ( gl ) {
+ var self = this,
+ shaderProgram;
+
+ shaderProgram = $.webgl.shader.addShaderProgram( self._gl, VERTEX_SHADER, FRAGMENT_SHADER );
+ gl.useProgram( shaderProgram );
+
+ shaderProgram.vertexPositionAttr = gl.getAttribLocation( shaderProgram, "aVertexPosition" );
+ gl.enableVertexAttribArray( shaderProgram.vertexPositionAttr );
+
+ shaderProgram.textureCoordAttr = gl.getAttribLocation( shaderProgram, "aTextureCoord" );
+ gl.enableVertexAttribArray( shaderProgram.textureCoordAttr );
+
+ // Set light normal vectors for lighting~
+ shaderProgram.vertexNormalAttr = gl.getAttribLocation( shaderProgram, "aVertexNormal" );
+ gl.enableVertexAttribArray( shaderProgram.vertexNormalAttr );
+
+ shaderProgram.perspectiveMU = gl.getUniformLocation( shaderProgram, "uPerspectiveMatrix");
+ shaderProgram.transformMU = gl.getUniformLocation( shaderProgram, "uMoveMatrix");
+ shaderProgram.sampleUniform = gl.getUniformLocation( shaderProgram, "uSampler");
+
+ // Set light variables~
+ shaderProgram.normalMU = gl.getUniformLocation( shaderProgram, "nNormalMatrix");
+ shaderProgram.ambientColorU = gl.getUniformLocation( shaderProgram, "uAmbientColor");
+ shaderProgram.lightDirU_first = gl.getUniformLocation( shaderProgram, "uLightDirection_first");
+ shaderProgram.lightDirU_second = gl.getUniformLocation( shaderProgram, "uLightDirection_second");
+ shaderProgram.directionColorU = gl.getUniformLocation( shaderProgram, "uDirectionColor");
+
+ return shaderProgram;
+ },
+
+ _initBuffers: function ( gl, shaderProgram ) {
+ var self = this,
+ i = 0,
+ mashBase = 0,
+ vertices = [],
+ textureCoords = [],
+ normalVectors = [],
+ nodes = [],
+ maxDrawLength = self._MAX_ITEM_COUNT;
+
+ for ( i = 0; i < self._imageList.length + 1; i += 1 ) {
+ nodes[i] = new Node();
+ $.merge( vertices, nodes[i].vertices );
+ $.merge( textureCoords, nodes[i].textureCoords );
+ $.merge( normalVectors, nodes[i].normalVectors );
+
+ nodes[i].textureBuffer = gl.createBuffer();
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, nodes[i].textureBuffer );
+ mashBase = i * 4;
+ nodes[i].meshOrder = [
+ mashBase, mashBase + 1, mashBase + 2,
+ mashBase + 2, mashBase + 3, mashBase
+ ];
+ gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new GlArray16( nodes[i].meshOrder ), gl.STATIC_DRAW );
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); // release buffer memory
+ nodes[i].textureBufferItemSize = 6;
+ }
+
+ self._positionBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( vertices ) );
+ self._positionBuffer.itemSize = 3;
+
+ self._textureCoordBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( textureCoords ) );
+ self._textureCoordBuffer.itemSize = 2;
+
+ self._normalVectorBuffer = $.webgl.buffer.attribBufferData( gl, new GlArray32( normalVectors ) ); // Vertex's normal vector for Direction light
+ self._normalVectorBuffer.itemSize = 3;
+
+ // Ambient light
+ gl.uniform3f( shaderProgram.ambientColorU, 0.1, 0.1, 0.1 );
+ // Direcntion light
+ gl.uniform3f( shaderProgram.directionColorU, 1.0, 1.0, 1.0 );
+
+ return nodes;
+ },
+
+ // ----------------------------------------------------------
+ // Texture
+ // ----------------------------------------------------------
+ _initTextures: function ( gl, nodes ) {
+ var self = this;
+
+ $( nodes ).each( function ( i ) {
+ var node = nodes[i],
+ url;
+
+ if ( !self._imageList[i] ) {
+ return false;
+ }
+
+ url = self._imageList[i].src;
+ node.texture = gl.createTexture();
+ self._loadImage( url, i, i, gl, nodes );
+ });
+ },
+
+ _loadImage: function ( url, i, imageID, gl, nodes ) {
+ var self = this,
+ isMipmap = false,
+ image,
+ node;
+
+ gl = gl || self._gl;
+ nodes = nodes || self._nodes;
+ isMipmap = isMipmap || false;
+ node = nodes[i];
+ node.image = node.image || new Image();
+
+ $( node.image ).one( "load", function ( e ) {
+ self._bindTexture( gl, node, this, isMipmap );
+ node.imageID = imageID;
+
+ if ( !self._animationID ) {
+ self._setPosition( 0, 0 );
+ }
+ });
+
+ if ( self.options.thumbnailCache ) {
+ $.imageloader.getThumbnail( url, function ( result ) {
+ if ( result === "NOT_FOUND_ERR" ) {
+ $.imageloader.setThumbnail( url, function ( result ) {
+ if ( result && result.length > 30 ) {
+ node.image.src = result;
+ isMipmap = true;
+ } else {
+ node.image.src = url;
+ }
+ });
+ } else if ( result && result.length > 30 ) {
+ node.image.src = result;
+ isMipmap = true;
+ } else {
+ node.image.src = url;
+ }
+ });
+ } else {
+ node.image.src = url;
+ }
+ },
+
+ _bindTexture: function ( gl, node, image, isMipmap ) {
+ if ( !node || !node.texture ) {
+ return;
+ }
+
+ gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true );
+
+ gl.bindTexture( gl.TEXTURE_2D, node.texture );
+ gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image );
+
+ if ( isMipmap ) {
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST );
+ gl.generateMipmap( gl.TEXTURE_2D );
+ } else {
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR );
+ }
+
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
+
+ node.texture.loaded = true;
+
+ // release texture memory
+ gl.bindTexture( gl.TEXTURE_2D, null );
+ },
+
+ // ----------------------------------------------------------
+ // rendering
+ // ----------------------------------------------------------
+ _setPosition: function ( progress, direction ) {
+ var self = this,
+ nodes = self._nodes,
+ imageList = self._imageList,
+ imageListLength = imageList.length,
+ itemCount = self._MAX_ITEM_COUNT,
+ displayLength = ( imageListLength > itemCount ) ? itemCount : imageListLength,
+ nextLevelLenth = 0,
+ i = 0,
+ t = 0,
+ position = 0,
+ angle = 0,
+ current = 0,
+ next = 0,
+ nextLevel = 0,
+ path = self._path,
+ nextImageID = 0;
+
+ nextLevelLenth = ( direction >= 0 ) ? displayLength + 1 : displayLength;
+
+ if ( !nodes[i].level ) {
+ nodes[i].level = displayLength;
+ }
+
+ for ( i = 0; i < displayLength; i += 1 ) {
+ if ( !nodes[i].mvMatrix ) {
+ nodes[i].mvMatrix = mat4.create();
+ }
+
+ if ( direction > 0 && nodes[i].level >= displayLength ) {
+ nodes[i].level = 0;
+ }
+
+ current = path.levels[nodes[i].level];
+ nextLevel = ( nodes[i].level + nextLevelLenth + direction ) % nextLevelLenth;
+ next = path.levels[nextLevel];
+
+ if ( imageListLength > itemCount ) {
+ if ( direction > 0 && nextLevel === 1
+ && self._firstImageNumber !== nodes[i].imageID ) {
+ self._loadImage( imageList[self._firstImageNumber].src, i, self._firstImageNumber );
+ } else if ( direction < 0 && nextLevel === nextLevelLenth - 1
+ && self._lastImageNumber !== nodes[i].imageID ) {
+ self._loadImage( imageList[self._lastImageNumber].src, i, self._lastImageNumber );
+ }
+ }
+
+ mat4.identity( nodes[i].mvMatrix );
+ mat4.translate( nodes[i].mvMatrix, [-2.0, -2.0, 1.0] );
+ mat4.rotate( nodes[i].mvMatrix, self._degreeToRadian( 19 ), [1, 0, 0] );
+
+ t = ( current + ( next - current ) * ( ( progress > 1 ) ? 1 : progress ) );
+
+ if ( progress >= self._ANIMATION_END ) {
+ nodes[i].level = nextLevel || displayLength;
+ t = path.levels[nodes[i].level];
+ }
+
+ if ( ( progress < self._ANIMATION_END )
+ && ( direction <= 0 && nodes[i].level < 1 ) ) {
+ nodes[i].drawable = false;
+ } else {
+ nodes[i].drawable = true;
+ }
+
+ if ( progress === self._ANIMATION_END && nodes[i].level === 1 ) {
+ self.element.trigger( "select", imageList[ nodes[i].imageID ], nodes[i].imageID );
+ }
+
+ position = path.getPosition( t );
+ angle = path.getAngle( t );
+
+ mat4.translate( nodes[i].mvMatrix, position );
+ mat4.rotate( nodes[i].mvMatrix, angle, [0, 1, 0] );
+ }
+
+ if ( imageListLength > itemCount && progress >= self._ANIMATION_END ) {
+ self._firstImageNumber = ( self._firstImageNumber - direction ) % imageListLength;
+ if ( self._firstImageNumber < 0 ) {
+ self._firstImageNumber = imageListLength - 1;
+ }
+
+ self._lastImageNumber = ( self._lastImageNumber - direction ) % imageListLength;
+ if ( self._lastImageNumber < 0 ) {
+ self._lastImageNumber = imageListLength - 1;
+ }
+ }
+ self._drawScene();
+ },
+
+ _drawScene: function () {
+ if ( !this._gl || !this._shaderProgram ) {
+ return;
+ }
+
+ var self = this,
+ gl = self._gl,
+ shaderProgram = self._shaderProgram,
+ nodes = self._nodes,
+ nodesLength = nodes.length,
+ i;
+
+ gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
+
+ gl.bindBuffer( gl.ARRAY_BUFFER, self._positionBuffer );
+ gl.vertexAttribPointer( shaderProgram.vertexPositionAttr, self._positionBuffer.itemSize, gl.FLOAT, false, 0, 0 );
+
+ gl.bindBuffer( gl.ARRAY_BUFFER, self._textureCoordBuffer );
+ gl.vertexAttribPointer( shaderProgram.textureCoordAttr, self._textureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0 );
+
+ gl.bindBuffer( gl.ARRAY_BUFFER, self._normalVectorBuffer );
+ gl.vertexAttribPointer( shaderProgram.vertexNormalAttr, self._normalVectorBuffer.itemSize, gl.FLOAT, false, 0, 0 );
+
+ for ( i = 0; i < nodesLength; i += 1 ) {
+ if ( nodes[i].drawable ) {
+ self._drawElement( self._pMatrix, nodes[i] );
+ }
+ }
+ },
+
+ _drawElement: function ( perspectiveMatrix, targetNode ) {
+ var self = this,
+ gl = self._gl,
+ shaderProgram = self._shaderProgram,
+ moveMatrix = targetNode.mvMatrix,
+ texture = targetNode.texture,
+ meshIndexBuffer = targetNode.textureBuffer,
+ meshIndexBufferItemSize = targetNode.textureBufferItemSize,
+ lightPositions = self._lightsPositionStack,
+ LightDir,
+ normalMatrix;
+
+ if ( !moveMatrix ) {
+ return;
+ }
+
+ gl.activeTexture( gl.TEXTURE0 );
+ if ( texture && texture.loaded ) {
+ gl.bindTexture( gl.TEXTURE_2D, texture );
+ }
+ gl.uniform1i( shaderProgram.sampleUniform, 0 );
+
+ LightDir = vec3.create();
+ vec3.normalize( lightPositions[0], LightDir );
+ vec3.scale( LightDir, -8 );
+ gl.uniform3fv( shaderProgram.lightDirU_first, LightDir );
+
+ vec3.normalize( lightPositions[1], LightDir );
+ vec3.scale( LightDir, -1 );
+ gl.uniform3fv( shaderProgram.lightDirU_second, LightDir );
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, meshIndexBuffer );
+
+ gl.uniformMatrix4fv( shaderProgram.perspectiveMU, false, perspectiveMatrix );
+ gl.uniformMatrix4fv( shaderProgram.transformMU, false, moveMatrix );
+
+ normalMatrix = mat3.create();
+ mat4.toInverseMat3( moveMatrix, normalMatrix );
+ mat3.transpose( normalMatrix );
+ gl.uniformMatrix3fv( shaderProgram.normalMU, false, normalMatrix );
+
+ gl.drawElements( gl.TRIANGLES, meshIndexBufferItemSize, gl.UNSIGNED_SHORT, 0 );
+
+ // release buffer memory
+ gl.bindBuffer( gl.ARRAY_BUFFER, null );
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null );
+
+ // release texture memory
+ gl.bindTexture( gl.TEXTURE_2D, null );
+ },
+
+ // ----------------------------------------------------------
+ // Animation
+ // ----------------------------------------------------------
+ _animate: function ( easingType, duration, direction, repeatCount, startValue, _removeCount ) {
+ var self = this,
+ timeNow = $.now(),
+ progress,
+ removeCount = 0;
+
+ easingType = easingType || "linear";
+ startValue = startValue || 0;
+ _removeCount = _removeCount || 0;
+
+ if ( self._sumTime >= duration ) {
+ self._setPosition( self._ANIMATION_END, direction );
+ self._stop();
+ return;
+ }
+
+ if ( self._startTime === 0 ) {
+ self._startTime = timeNow;
+ } else {
+ self._sumTime = timeNow - self._startTime;
+ progress = $.easing[ easingType ]( self._sumTime / duration, self._sumTime, startValue, repeatCount + 1, duration );
+ removeCount = parseInt( Math.abs( progress ), 10 );
+
+ if ( _removeCount !== removeCount ) {
+ self._setPosition( self._ANIMATION_END, direction );
+ _removeCount = removeCount;
+
+ if ( ( repeatCount - _removeCount ) >= 0 ) {
+ self._animate( easingType, duration, direction, repeatCount, startValue, _removeCount );
+ } else {
+ self._stop();
+ }
+ return;
+ }
+
+ self._setPosition( progress - _removeCount, direction );
+ }
+
+ self._animationID = window.requestAnimationFrame( function () {
+ self._animate( easingType, duration, direction, repeatCount, startValue, _removeCount );
+ });
+ },
+
+ _run: function ( direction, repeatCount, startValue ) {
+ var self = this,
+ repeat = repeatCount || 0,
+ duration = self._DURATION_DEFAULT * ( repeat + 1 );
+
+ if ( self._imageList.length <= 1 ) {
+ return;
+ }
+
+ startValue = startValue || 0;
+ duration = ( duration >= 0 ) ? duration : 0;
+
+ if ( self._animationID ) {
+ self._setPosition( self._ANIMATION_END, direction );
+ self._stop();
+ }
+
+ self._animate( "easeOutExpo", duration, direction, repeat, startValue );
+ },
+
+ _reset: function () {
+ if ( !this._canvas || !this._gl ) {
+ return;
+ }
+
+ this._final();
+ this._init();
+ this.refresh();
+ },
+
+ _stop: function () {
+ if ( this._animationID ) {
+ window.cancelAnimationFrame( this._animationID );
+ }
+ this._animationID = 0;
+
+ this._startTime = 0;
+ this._sumTime = 0;
+ },
+
+ _degreeToRadian: function ( degree ) {
+ return degree * Math.PI / 180;
+ },
+
+ next: function () {
+ this._run( this._DIRECTION_LEFT , 0 );
+ },
+
+ prev: function () {
+ this._run( this._DIRECTION_RIGHT, 0 );
+ },
+
+ refresh: function () {
+ var view = this.element,
+ canvas = view.find( "canvas.ui-gallery3d-canvas" );
+
+ if ( canvas.width() !== view.width() ) {
+ canvas.width( view.width() );
+ }
+
+ if ( !this._animationID ) {
+ this._setPosition( 0, 0 );
+ }
+ },
+
+ select: function ( index ) {
+ var nodes = this._nodes,
+ repeat,
+ i,
+ imageID,
+ object = null,
+ target = 0,
+ direction = 0;
+
+ if ( index && this._animationID ) {
+ this._stop();
+ }
+
+ for ( i in nodes ) {
+ if ( nodes[i].level === 1 ) {
+ object = this._imageList[ nodes[i].imageID ];
+ imageID = nodes[i].imageID;
+ break;
+ }
+ }
+
+ if ( !index ) {
+ return object;
+ }
+
+ if ( index < 0 && index >= this._imageList.length ) {
+ return;
+ }
+
+ target = index - imageID;
+ direction = ( target > 0 ) ? this._DIRECTION_LEFT
+ : ( ( target < 0 ) ? this._DIRECTION_RIGHT : 0 );
+ if ( direction ) {
+ this._run( direction, Math.abs( target ) - 1 );
+ }
+ },
+
+ add: function ( item, index ) {
+ if ( !item ) {
+ return;
+ }
+
+ if ( typeof item === "string" ) {
+ item = { "src" : item };
+ }
+
+ index = index || 0;
+ if ( typeof index !== "number" && index < 0
+ && index >= this._imageList.length ) {
+ return;
+ }
+
+ this._imageList.splice( index, 0, item );
+ if ( this._gl ) {
+ this._reset();
+ }
+ },
+
+ remove: function ( index ) {
+ index = index || 0;
+ if ( typeof index !== "number" && index < 0
+ && index >= this._imageList.length ) {
+ return;
+ }
+
+ this._imageList.splice( index, 1 );
+ if ( this._gl ) {
+ this._reset();
+ }
+ },
+
+ clearThumbnailCache: function () {
+ if ( !this._nodes || ( this._nodes.length <= 0 ) ) {
+ return;
+ }
+
+ var i, url;
+ for ( i = 0; i < this._imageList.length; i += 1 ) {
+ url = this._imageList[i].src;
+ $.imageloader.removeThumbnail( url );
+ }
+ },
+
+ empty: function () {
+ this._imageList = [];
+ this._reset();
+ },
+
+ length: function () {
+ return this._imageList.length;
+ }
+ });
+
+ $( document ).bind( "pagecreate create", function ( e ) {
+ $( ":jqmData(role='gallery3d')" ).gallery3d();
+ });
+
+} ( jQuery, document, window ) );
+
+//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
+} );
//>>excludeEnd("jqmBuildExclude");
\ No newline at end of file