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