ea2df91d36bf9fcd3184a8cedb37f2fcfafb89a6
[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 struct GeometryHintPair
41 {
42   const char* name;
43   ShaderEffect::GeometryHints hint;
44 };
45
46 const GeometryHintPair GeometryHintTable[]=
47 {
48     {"gridX",        ShaderEffect::HINT_GRID_X },
49     {"gridY",        ShaderEffect::HINT_GRID_Y },
50     {"grid",         ShaderEffect::HINT_GRID   },
51     {"depthBuffer",  ShaderEffect::HINT_DEPTH_BUFFER },
52     {"blending",     ShaderEffect::HINT_BLENDING },
53     {"doesntModifyGeometry", ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY }
54 };
55
56 const unsigned int GeometryHintTableCount = sizeof(GeometryHintTable)/sizeof(GeometryHintTable[0]);
57
58
59
60
61 struct ShaderParameters
62 {
63   ShaderParameters()
64       : mHints( ShaderEffect::HINT_NONE )
65   {
66   }
67
68   ShaderEffect::GeometryHints GetGeometryHint( const std::string& hint )
69   {
70     for( unsigned int i = 0 ; i < GeometryHintTableCount; ++i )
71     {
72       if( hint == GeometryHintTable[i].name )
73       {
74         return GeometryHintTable[i].hint;
75       }
76     }
77     return ShaderEffect::HINT_NONE;
78   }
79
80   void ProcessHintsArray( const HintsArray& hintsArray )
81   {
82     for( HintsArray::const_iterator iter  = hintsArray.begin(); iter != hintsArray.end() ; ++iter )
83     {
84       mHints= static_cast<ShaderEffect::GeometryHints>( mHints | GetGeometryHint( *iter ) );
85     }
86   }
87
88   ShaderEffect NewShader()
89   {
90     return ShaderEffect::NewWithPrefix( mVertexPrefix ,
91                               mVertex,
92                               mFragmentPrefix,
93                               mFragment,
94                               mHints);
95   }
96   std::string mVertexPrefix;
97   std::string mVertex;
98   std::string mFragmentPrefix;
99   std::string mFragment;
100   ShaderEffect::GeometryHints mHints;
101 };
102
103 ShaderEffect GetShaderEffect( v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
104 {
105   v8::HandleScope handleScope( isolate );
106
107   v8::Local<v8::Object> object = args.This();
108   v8::Local<v8::External> field = v8::Local<v8::External>::Cast( object->GetInternalField(0) );
109   void* ptr = field->Value();
110
111   ShaderEffectWrapper* wrapper = static_cast< ShaderEffectWrapper *>(ptr);
112   return wrapper->GetShaderEffect();
113 }
114
115 } // unnamed space
116
117 /**
118  * Create a new ShaderEffect
119  * @constructor
120  * @for ShaderEffect
121  * @method ShaderEffect
122  * @param {Object} shaderOptions
123  * @param {String} [shaderOptions.geometryType] Type of geometry to be rendered with the effect. "image", "text", "mesh", "texturedMesh",  default is image.
124  * @param {String} [shaderOptions.vertexShaderPrefix] This string will be inserted before the default uniforms for the vertex shader(ideal for #defines)
125  * @param {String} [shaderOptions.vertexShader] VertexShader code for the effect. If not defined, the default version will be used
126  * @param {String} [shaderOptions.fragmentShaderPrefix] This string will be inserted before the default uniforms for the fragment shader(ideal for #defines)
127  * @param {String} [shaderOptions.fragmentShader] FragmentShader code for the effect. If not defined, the default version will be used
128  * @param {Array}  [shaderOptions.geometryHints] Hints for rendering the geometry, e.g.  [ "gridX", "gridY", "grid","depthBuffer","blending","doesntModifyGeometry" ]
129  * @return {Object} ShaderEffect
130  * @example
131
132       // this will match the default shaders for image
133       var vertexShader = " void main() \
134       { \
135         gl_Position = uProjection * uModelView * vec4(aPosition, 1.0); \
136         vTexCoord = aTexCoord; \
137       }; "
138      var fragShader = " void main() \
139       { \
140        gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\
141       }; "
142       var shaderOptions = {
143             geometryType: "image",
144             vertexShader: vertexShader,
145             fragmentShader: fragShader
146       };
147
148       var shader = new dali.ShaderEffect(shaderOptions);
149
150       imageActor.setShaderEffect( shader );
151
152  *
153  *
154  *
155  */
156 ShaderEffect ShaderEffectApi::New(  v8::Isolate* isolate, const v8::FunctionCallbackInfo< v8::Value >& args )
157 {
158   v8::HandleScope handleScope( isolate );
159
160   if( args[0]->IsObject() )
161   {
162     ShaderParameters shaderParams;
163
164     v8::Local<v8::Object > obj = args[0]->ToObject();
165
166     v8::Local<v8::Value> vertexPrefixValue = obj->Get(v8::String::NewFromUtf8( isolate, "vertexShaderPrefix"));
167     if( vertexPrefixValue->IsString() )
168     {
169       shaderParams.mVertexPrefix = V8Utils::v8StringToStdString( vertexPrefixValue );
170     }
171
172     v8::Local<v8::Value> fragmentPrefixValue = obj->Get(v8::String::NewFromUtf8( isolate, "fragmentShaderPrefix"));
173     if( fragmentPrefixValue->IsString() )
174     {
175       shaderParams.mFragmentPrefix = V8Utils::v8StringToStdString( fragmentPrefixValue );
176     }
177
178     v8::Local<v8::Value> vertexValue = obj->Get(v8::String::NewFromUtf8( isolate, "vertexShader"));
179     if( vertexValue->IsString() )
180     {
181       shaderParams.mVertex = V8Utils::v8StringToStdString( vertexValue );
182     }
183
184     v8::Local<v8::Value> fragmentValue = obj->Get(v8::String::NewFromUtf8( isolate, "fragmentShader"));
185     if( fragmentValue->IsString() )
186     {
187       shaderParams.mFragment = V8Utils::v8StringToStdString( fragmentValue );
188     }
189     // Get any hints
190     v8::Local<v8::Value> hints = obj->Get(v8::String::NewFromUtf8( isolate, "geometryHints"));
191     if( hints->IsArray() )
192     {
193       HintsArray hintsArray;
194       v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast( hints );
195       for( uint32_t i=0; i <  array->Length(); ++i)
196       {
197         v8::Handle<v8::Value> entry = array->Get(  v8::Integer::New( isolate, i) );
198         if( entry->IsString() )
199         {
200           std::string entryString = V8Utils::v8StringToStdString( entry );
201           hintsArray.push_back( entryString );
202         }
203       }
204       shaderParams.ProcessHintsArray( hintsArray );
205     }
206
207     return shaderParams.NewShader();
208   }
209   else
210   {
211     ShaderEffect effect;
212
213     bool found( false );
214     std::string typeName = V8Utils::GetStringParameter( PARAMETER_0, found, isolate, args );
215     if( !found )
216     {
217       DALI_SCRIPT_EXCEPTION( isolate, "string parameter missing" );
218     }
219     else
220     {
221       // create a new shader effect based on type, using the type registry.
222       Dali::TypeInfo typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( typeName );
223       if( typeInfo ) // handle, check if it has a value
224       {
225         Dali::BaseHandle handle = typeInfo.CreateInstance();
226         if( handle )
227         {
228           effect = ShaderEffect::DownCast( handle );
229         }
230       }
231       else
232       {
233         DALI_SCRIPT_EXCEPTION(isolate,"Unknown shader effect type");
234       }
235     }
236
237     return effect;
238   }
239 }
240
241 ShaderEffect ShaderEffectApi::GetShaderEffectFromParams( int paramIndex,
242                           bool& found,
243                           v8::Isolate* isolate,
244                           const v8::FunctionCallbackInfo< v8::Value >& args )
245 {
246   found = false;
247
248   v8::HandleScope handleScope( isolate );
249   BaseWrappedObject* wrappedObject = V8Utils::GetWrappedDaliObjectParameter( paramIndex, BaseWrappedObject::SHADER_EFFECT, isolate, args );
250   if( wrappedObject )
251   {
252     found = true;
253     ShaderEffectWrapper* wrapper = static_cast< ShaderEffectWrapper *>(wrappedObject);
254     return wrapper->GetShaderEffect();
255   }
256   else
257   {
258     return ShaderEffect();
259   }
260 }
261
262 /**
263  * Set a shader effect image.
264  * This image texture will be bound to the "sEffect" sampler
265  * so it can be used in fragment shader for effects
266  * @method setEffectImage
267  * @for ShaderEffect
268  * @param {Object} image
269  * @example
270  *
271  *      shader.setEffectImage( image );
272  *
273  *      // example of a fragment shader than can use the effect image (sEffect and main texture sTexture)
274  *
275  *      "void main() \
276  *       { \
277  *        vec4 v4Color  = (texture2D(sTexture, vTexCoord) * uColor); \
278  *        v4Color = v4Color*  texture2D(sEffect, vTexCoord);\
279  *        gl_FragColor = v4Color; \"
280  *      }";
281  */
282 void ShaderEffectApi::SetEffectImage( const v8::FunctionCallbackInfo< v8::Value >& args )
283 {
284   v8::Isolate* isolate = args.GetIsolate();
285   v8::HandleScope handleScope( isolate );
286
287   bool found( false );
288   Image image = V8Utils::GetImageParameter( PARAMETER_0, found, isolate, args );
289   if( !found )
290   {
291     DALI_SCRIPT_EXCEPTION( isolate, " Image::SetEffectImage invalid params");
292     return;
293   }
294   ShaderEffect effect =  GetShaderEffect( isolate, args );
295   effect.SetEffectImage( image );
296 }
297
298
299 /**
300  * Sets and registers a uniform property.
301  * If name matches a uniform in the shader source, this value will be uploaded when rendering.
302  * This uniform can then be animated / modified and the change will be made to the shader.
303  * @method setUniform
304  * @for ShaderEffect
305  * @param {String} name
306  * @param {Object} value must be a: float, vector2 vector3, vector4, matrix
307  * @param {String} [uniformCoordinateType] The coordinate type of the uniform.
308  * either "viewPortPosition" or "viewPortDirection"
309  * @example
310
311       var fragShader =
312       " uniform lowp vec4 uColorShift; \
313       \
314        void main()             \
315        {                  \
316
317          gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor + uColorShift; \
318        }"
319
320       var shaderOptions = {
321           geometryType: "image",
322           fragmentShader: fragShader
323       };
324
325       // create a new shader effect
326       var shader = new dali.ShaderEffect(shaderOptions);
327
328       // add the color shift uniform so we can animate it
329       // default the color shift to zero, so it has no effect
330       shader.setUniform("uColorShift", [0.0, 0.0, 0.0, 0]);
331  */
332 void ShaderEffectApi::SetUniform( const v8::FunctionCallbackInfo< v8::Value >& args )
333 {
334
335   v8::Isolate* isolate = args.GetIsolate();
336   v8::HandleScope handleScope( isolate );
337   ShaderEffect effect =  GetShaderEffect( isolate, args );
338
339   bool found(false);
340   std::string uniformName = V8Utils::GetStringParameter( PARAMETER_0 , found, isolate, args );
341   if( !found )
342   {
343     DALI_SCRIPT_EXCEPTION( isolate, "SetUniform: uniform name not found\n");
344     return;
345   }
346
347   Property::Value propValue = V8Utils::GetPropertyValueParameter( PARAMETER_1 , found, isolate, args );
348   if( !found )
349   {
350     DALI_SCRIPT_EXCEPTION( isolate, "SetUniform: value not found\n");
351     return;
352   }
353
354   std::string coordinateType = V8Utils::GetStringParameter( PARAMETER_2, found, isolate, args );
355   ShaderEffect::UniformCoordinateType uniformCoordinateType( ShaderEffect::COORDINATE_TYPE_DEFAULT );
356   if( found )
357   {
358     if( coordinateType == "viewPortPosition")
359     {
360       uniformCoordinateType = ShaderEffect::COORDINATE_TYPE_VIEWPORT_POSITION;
361     }
362     else if ( coordinateType == "viewPortDirection ")
363     {
364       uniformCoordinateType = ShaderEffect::COORDINATE_TYPE_VIEWPORT_DIRECTION;
365     }
366   }
367
368   switch( propValue.GetType() )
369   {
370     case Property::FLOAT:
371     {
372       effect.SetUniform( uniformName, propValue.Get<float>(), uniformCoordinateType );
373       break;
374     }
375     case Property::VECTOR2:
376     {
377       effect.SetUniform( uniformName, propValue.Get<Vector2>(), uniformCoordinateType );
378       break;
379     }
380     case Property::VECTOR3:
381     {
382       effect.SetUniform( uniformName, propValue.Get<Vector3>(), uniformCoordinateType );
383       break;
384     }
385     case Property::VECTOR4:
386     {
387       effect.SetUniform( uniformName, propValue.Get<Vector4>(), uniformCoordinateType );
388       break;
389     }
390     case Property::MATRIX:
391     {
392       effect.SetUniform( uniformName, propValue.Get<Matrix>(), uniformCoordinateType );
393       break;
394     }
395     case Property::MATRIX3:
396     {
397       effect.SetUniform( uniformName, propValue.Get<Matrix3>(), uniformCoordinateType );
398       break;
399     }
400     default:
401     {
402       DALI_SCRIPT_EXCEPTION( isolate, "value type not recognised \n");
403       break;
404     }
405   }
406 }
407
408
409 } // namespace V8Plugin
410
411 } // namespace Dali