Merge "OnActivated() change for Accessibility and KeyboardFocus" into devel/master
[platform/core/uifw/dali-toolkit.git] / plugins / dali-script-v8 / src / shader-effects / shader-effect-api.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18
19 // CLASS HEADER
20 #include "shader-effect-api.h"
21
22 // EXTERNAL INCLUDES
23 #include <dali/public-api/object/type-registry.h>
24
25 // INTERNAL INCLUDES
26 #include <v8-utils.h>
27 #include <shader-effects/shader-effect-wrapper.h>
28
29 namespace Dali
30 {
31
32 namespace V8Plugin
33 {
34
35 namespace // un named namespace
36 {
37
38 typedef  std::vector< std::string > HintsArray;
39
40
41 struct GeometryTypePair
42 {
43   const char* name;
44   GeometryType type;
45 };
46
47 const GeometryTypePair GeometryTypeTable[]=
48 {
49     {"image",         GEOMETRY_TYPE_IMAGE },
50     {"mesh",          GEOMETRY_TYPE_UNTEXTURED_MESH  },
51     {"textured-mesh", GEOMETRY_TYPE_TEXTURED_MESH },
52 };
53
54 const unsigned int GeometryTypeTableCount = sizeof(GeometryTypeTable)/sizeof(GeometryTypeTable[0]);
55
56 struct GeometryHintPair
57 {
58   const char* name;
59   ShaderEffect::GeometryHints hint;
60 };
61
62 const GeometryHintPair GeometryHintTable[]=
63 {
64     {"gridX",        ShaderEffect::HINT_GRID_X },
65     {"gridY",        ShaderEffect::HINT_GRID_Y },
66     {"grid",         ShaderEffect::HINT_GRID   },
67     {"depthBuffer",  ShaderEffect::HINT_DEPTH_BUFFER },
68     {"blending",     ShaderEffect::HINT_BLENDING },
69     {"doesntModifyGeometry", ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY }
70 };
71
72 const unsigned int GeometryHintTableCount = sizeof(GeometryHintTable)/sizeof(GeometryHintTable[0]);
73
74
75
76
77 struct ShaderParameters
78 {
79   ShaderParameters()
80       : mType( GEOMETRY_TYPE_IMAGE),
81         mHints( ShaderEffect::HINT_NONE )
82   {
83   }
84
85   void SetGeometryType( v8::Isolate* isolate, const std::string& typeName )
86   {
87      for( unsigned int i = 0; i < GeometryTypeTableCount; ++i )
88      {
89        if( typeName == GeometryTypeTable[i].name )
90        {
91          mType = GeometryTypeTable[i].type;
92          return;
93        }
94      }
95      DALI_SCRIPT_EXCEPTION( isolate, "Geometry type not found\n");
96   }
97
98   ShaderEffect::GeometryHints GetGeometryHint( const std::string& hint )
99   {
100     for( unsigned int i = 0 ; i < GeometryHintTableCount; ++i )
101     {
102       if( hint == GeometryHintTable[i].name )
103       {
104         return GeometryHintTable[i].hint;
105       }
106     }
107     return ShaderEffect::HINT_NONE;
108   }
109
110   void ProcessHintsArray( const HintsArray& hintsArray )
111   {
112     for( HintsArray::const_iterator iter  = hintsArray.begin(); iter != hintsArray.end() ; ++iter )
113     {
114       mHints= static_cast<ShaderEffect::GeometryHints>( mHints | GetGeometryHint( *iter ) );
115     }
116   }
117
118
119
120   ShaderEffect NewShader()
121   {
122     return ShaderEffect::NewWithPrefix( mVertexPrefix ,
123                               mVertex,
124                               mFragmentPrefix,
125                               mFragment,
126                               mType,
127                               mHints);
128   }
129   std::string mVertexPrefix;
130   std::string mVertex;
131   std::string mFragmentPrefix;
132   std::string mFragment;
133   GeometryType mType;
134   ShaderEffect::GeometryHints mHints;
135 };
136
137 ShaderEffect GetShaderEffect( v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
138 {
139   v8::HandleScope handleScope( isolate );
140
141   v8::Local<v8::Object> object = args.This();
142   v8::Local<v8::External> field = v8::Local<v8::External>::Cast( object->GetInternalField(0) );
143   void* ptr = field->Value();
144
145   ShaderEffectWrapper* wrapper = static_cast< ShaderEffectWrapper *>(ptr);
146   return wrapper->GetShaderEffect();
147 }
148
149 } // unnamed space
150
151 /**
152  * Create a new ShaderEffect
153  * @constructor
154  * @for ShaderEffect
155  * @method ShaderEffect
156  * @param {Object} shaderOptions
157  * @param {String} [shaderOptions.geometryType] Type of geometry to be rendered with the effect. "image", "text", "mesh", "textured-mesh", default is image.
158  * @param {String} [shaderOptions.vertexShaderPrefix] This string will be inserted before the default uniforms for the vertex shader(ideal for #defines)
159  * @param {String} [shaderOptions.vertexShader] VertexShader code for the effect. If not defined, the default version will be used
160  * @param {String} [shaderOptions.fragmentShaderPrefix] This string will be inserted before the default uniforms for the fragment shader(ideal for #defines)
161  * @param {String} [shaderOptions.fragmentShader] FragmentShader code for the effect. If not defined, the default version will be used
162  * @param {Array}  [shaderOptions.geometryHints] Hints for rendering the geometry, e.g.  [ "gridX", "gridY", "grid","depthBuffer","blending","doesntModifyGeometry" ]
163  * @return {Object} ShaderEffect
164  * @example
165
166       // this will match the default shaders for image
167       var vertexShader = " void main() \
168       { \
169         gl_Position = uProjection * uModelView * vec4(aPosition, 1.0); \
170         vTexCoord = aTexCoord; \
171       }; "
172      var fragShader = " void main() \
173       { \
174        gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\
175       }; "
176       var shaderOptions = {
177             geometryType: "image",
178             vertexShader: vertexShader,
179             fragmentShader: fragShader
180       };
181
182       var shader = new dali.ShaderEffect(shaderOptions);
183
184       imageActor.setShaderEffect( shader );
185
186  *
187  *
188  *
189  */
190 ShaderEffect ShaderEffectApi::New(  v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
191 {
192   v8::HandleScope handleScope( isolate );
193
194   if( args[0]->IsObject() )
195   {
196     ShaderParameters shaderParams;
197
198     v8::Local<v8::Object > obj = args[0]->ToObject();
199
200     v8::Local<v8::Value> geometryTypeValue = obj->Get(v8::String::NewFromUtf8( isolate, "geometryType"));
201     if( geometryTypeValue->IsString() )
202     {
203       std::string geometryTypeName = V8Utils::v8StringToStdString( geometryTypeValue );
204      // printf(" geometry type found %s \n", geometryTypeName.c_str() );
205       shaderParams.SetGeometryType( isolate, geometryTypeName );
206     }
207
208     v8::Local<v8::Value> vertexPrefixValue = obj->Get(v8::String::NewFromUtf8( isolate, "vertexShaderPrefix"));
209     if( vertexPrefixValue->IsString() )
210     {
211       shaderParams.mVertexPrefix = V8Utils::v8StringToStdString( vertexPrefixValue );
212     }
213
214     v8::Local<v8::Value> fragmentPrefixValue = obj->Get(v8::String::NewFromUtf8( isolate, "fragmentShaderPrefix"));
215     if( fragmentPrefixValue->IsString() )
216     {
217       shaderParams.mFragmentPrefix = V8Utils::v8StringToStdString( fragmentPrefixValue );
218     }
219
220     v8::Local<v8::Value> vertexValue = obj->Get(v8::String::NewFromUtf8( isolate, "vertexShader"));
221     if( vertexValue->IsString() )
222     {
223       shaderParams.mVertex = V8Utils::v8StringToStdString( vertexValue );
224     }
225
226     v8::Local<v8::Value> fragmentValue = obj->Get(v8::String::NewFromUtf8( isolate, "fragmentShader"));
227     if( fragmentValue->IsString() )
228     {
229       shaderParams.mFragment = V8Utils::v8StringToStdString( fragmentValue );
230     }
231     // Get any hints
232     v8::Local<v8::Value> hints = obj->Get(v8::String::NewFromUtf8( isolate, "geometryHints"));
233     if( hints->IsArray() )
234     {
235       HintsArray hintsArray;
236       v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast( hints );
237       for( uint32_t i=0; i <  array->Length(); ++i)
238       {
239         v8::Handle<v8::Value> entry = array->Get(  v8::Integer::New( isolate, i) );
240         if( entry->IsString() )
241         {
242           std::string entryString = V8Utils::v8StringToStdString( entry );
243           hintsArray.push_back( entryString );
244         }
245       }
246       shaderParams.ProcessHintsArray( hintsArray );
247     }
248
249     return shaderParams.NewShader();
250   }
251   else
252   {
253     ShaderEffect effect;
254
255     bool found( false );
256     std::string typeName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args );
257     if( !found )
258     {
259       DALI_SCRIPT_EXCEPTION( isolate, "string parameter missing" );
260     }
261     else
262     {
263       // create a new shader effect based on type, using the type registry.
264       Dali::TypeInfo typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( typeName );
265       if( typeInfo ) // handle, check if it has a value
266       {
267         Dali::BaseHandle handle = typeInfo.CreateInstance();
268         if( handle )
269         {
270           effect = ShaderEffect::DownCast( handle );
271         }
272       }
273       else
274       {
275         DALI_SCRIPT_EXCEPTION(isolate,"Unknown shader effect type");
276       }
277     }
278
279     return effect;
280   }
281 }
282
283 ShaderEffect ShaderEffectApi::GetShaderEffectFromParams( int paramIndex,
284                           bool& found,
285                           v8::Isolate* isolate,
286                           const v8::FunctionCallbackInfo< v8::Value >& args )
287 {
288   found = false;
289
290   v8::HandleScope handleScope( isolate );
291   BaseWrappedObject* wrappedObject = V8Utils::GetWrappedDaliObjectParameter( paramIndex, BaseWrappedObject::SHADER_EFFECT, isolate, args );
292   if( wrappedObject )
293   {
294     found = true;
295     ShaderEffectWrapper* wrapper = static_cast< ShaderEffectWrapper *>(wrappedObject);
296     return wrapper->GetShaderEffect();
297   }
298   else
299   {
300     return ShaderEffect();
301   }
302 }
303
304 /**
305  * Set a shader effect image.
306  * This image texture will be bound to the "sEffect" sampler
307  * so it can be used in fragment shader for effects
308  * @method setEffectImage
309  * @for ShaderEffect
310  * @param {Object} image
311  * @example
312  *
313  *      shader.setEffectImage( image );
314  *
315  *      // example of a fragment shader than can use the effect image (sEffect and main texture sTexture)
316  *
317  *      "void main() \
318  *       { \
319  *        vec4 v4Color  = (texture2D(sTexture, vTexCoord) * uColor); \
320  *        v4Color = v4Color*  texture2D(sEffect, vTexCoord);\
321  *        gl_FragColor = v4Color; \"
322  *      }";
323  */
324 void ShaderEffectApi::SetEffectImage( const v8::FunctionCallbackInfo< v8::Value >& args )
325 {
326   v8::Isolate* isolate = args.GetIsolate();
327   v8::HandleScope handleScope( isolate );
328
329   bool found( false );
330   Image image = V8Utils::GetImageParameter( PARAMETER_0, found, isolate, args );
331   if( !found )
332   {
333     DALI_SCRIPT_EXCEPTION( isolate, " Image::SetEffectImage invalid params");
334     return;
335   }
336   ShaderEffect effect =  GetShaderEffect( isolate, args );
337   effect.SetEffectImage( image );
338 }
339
340
341 /**
342  * Sets and registers a uniform property.
343  * If name matches a uniform in the shader source, this value will be uploaded when rendering.
344  * This uniform can then be animated / modified and the change will be made to the shader.
345  * @method setUniform
346  * @for ShaderEffect
347  * @param {String} name
348  * @param {Object} value must be a: float, vector2 vector3, vector4, matrix
349  * @param {String} [uniformCoordinateType] The coordinate type of the uniform.
350  * either "viewPortPosition" or "viewPortDirection"
351  * @example
352
353       var fragShader =
354       " uniform lowp vec4 uColorShift; \
355       \
356        void main()             \
357        {                  \
358
359          gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor + uColorShift; \
360        }"
361
362       var shaderOptions = {
363           geometryType: "image",
364           fragmentShader: fragShader
365       };
366
367       // create a new shader effect
368       var shader = new dali.ShaderEffect(shaderOptions);
369
370       // add the color shift uniform so we can animate it
371       // default the color shift to zero, so it has no effect
372       shader.setUniform("uColorShift", [0.0, 0.0, 0.0, 0]);
373  */
374 void ShaderEffectApi::SetUniform( const v8::FunctionCallbackInfo< v8::Value >& args )
375 {
376
377   v8::Isolate* isolate = args.GetIsolate();
378   v8::HandleScope handleScope( isolate );
379   ShaderEffect effect =  GetShaderEffect( isolate, args );
380
381   bool found(false);
382   std::string uniformName = V8Utils::GetStringParameter( PARAMETER_0 , found, isolate, args );
383   if( !found )
384   {
385     DALI_SCRIPT_EXCEPTION( isolate, "SetUniform: uniform name not found\n");
386     return;
387   }
388
389   Property::Value propValue = V8Utils::GetPropertyValueParameter( PARAMETER_1 , found, isolate, args );
390   if( !found )
391   {
392     DALI_SCRIPT_EXCEPTION( isolate, "SetUniform: value not found\n");
393     return;
394   }
395
396   std::string coordinateType = V8Utils::GetStringParameter( PARAMETER_2, found, isolate, args );
397   ShaderEffect::UniformCoordinateType uniformCoordinateType( ShaderEffect::COORDINATE_TYPE_DEFAULT );
398   if( found )
399   {
400     if( coordinateType == "viewPortPosition")
401     {
402       uniformCoordinateType = ShaderEffect::COORDINATE_TYPE_VIEWPORT_POSITION;
403     }
404     else if ( coordinateType == "viewPortDirection ")
405     {
406       uniformCoordinateType = ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION;
407     }
408   }
409
410   switch( propValue.GetType() )
411   {
412     case Property::FLOAT:
413     {
414       effect.SetUniform( uniformName, propValue.Get<float>(), uniformCoordinateType );
415       break;
416     }
417     case Property::VECTOR2:
418     {
419       effect.SetUniform( uniformName, propValue.Get<Vector2>(), uniformCoordinateType );
420       break;
421     }
422     case Property::VECTOR3:
423     {
424       effect.SetUniform( uniformName, propValue.Get<Vector3>(), uniformCoordinateType );
425       break;
426     }
427     case Property::VECTOR4:
428     {
429       effect.SetUniform( uniformName, propValue.Get<Vector4>(), uniformCoordinateType );
430       break;
431     }
432     case Property::MATRIX:
433     {
434       effect.SetUniform( uniformName, propValue.Get<Matrix>(), uniformCoordinateType );
435       break;
436     }
437     case Property::MATRIX3:
438     {
439       effect.SetUniform( uniformName, propValue.Get<Matrix3>(), uniformCoordinateType );
440       break;
441     }
442     default:
443     {
444       DALI_SCRIPT_EXCEPTION( isolate, "value type not recognised \n");
445       break;
446     }
447   }
448 }
449
450
451 } // namespace V8Plugin
452
453 } // namespace Dali