Fix Scene3d-View light issue
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scene3d-view / scene3d-view-impl.cpp
1 /*
2  * Copyright (c) 2021 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 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
26
27 namespace Dali
28 {
29 namespace Toolkit
30 {
31 namespace Internal
32 {
33 namespace
34 {
35 const char* const IMAGE_BRDF_FILE_NAME = "brdfLUT.png";
36
37 // glTF file extension
38 const std::string GLTF_EXT(".gltf");
39
40 /**
41  * cube map face index
42  */
43 const uint32_t CUBEMAP_INDEX_X[2][6] = {{2, 0, 1, 1, 1, 3}, {0, 1, 2, 3, 4, 5}};
44 const uint32_t CUBEMAP_INDEX_Y[2][6] = {{1, 1, 0, 2, 1, 1}, {0, 0, 0, 0, 0, 0}};
45
46 } //namespace
47
48 Scene3dView::Scene3dView()
49 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
50   mRoot(Actor::New()),
51   mShaderArray(),
52   mCameraActorArray(),
53   mDefaultCamera(CameraActor::New()),
54   mAnimationArray(),
55   mLightType(Toolkit::Scene3dView::LightType::NONE),
56   mLightVector(Vector3::ONE),
57   mLightColor(Vector3::ONE),
58   mUseIBL(false)
59 {
60 }
61
62 Scene3dView::~Scene3dView()
63 {
64 }
65
66 Toolkit::Scene3dView Scene3dView::New(const std::string& filePath)
67 {
68   Scene3dView* impl = new Scene3dView();
69
70   Dali::Toolkit::Scene3dView handle = Dali::Toolkit::Scene3dView(*impl);
71
72   // Second-phase init of the implementation
73   // This can only be done after the CustomActor connection has been made...
74   impl->mFilePath = filePath;
75   impl->Initialize();
76
77   return handle;
78 }
79
80 Toolkit::Scene3dView Scene3dView::New(const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor)
81 {
82   Scene3dView* impl = new Scene3dView();
83
84   Dali::Toolkit::Scene3dView handle = Dali::Toolkit::Scene3dView(*impl);
85
86   // Second-phase init of the implementation
87   // This can only be done after the CustomActor connection has been made...
88   impl->mFilePath = filePath;
89   impl->SetCubeMap(diffuseTexturePath, specularTexturePath, scaleFactor);
90   impl->Initialize();
91
92   return handle;
93 }
94
95 bool Scene3dView::CreateScene()
96 {
97   if(std::string::npos != mFilePath.rfind(GLTF_EXT))
98   {
99     Internal::Gltf::Loader gltfloader;
100     return (gltfloader.LoadScene(mFilePath, *this));
101   }
102
103   return false;
104 }
105
106 uint32_t Scene3dView::GetAnimationCount()
107 {
108   return mAnimationArray.size();
109 }
110
111 bool Scene3dView::PlayAnimation(uint32_t index)
112 {
113   if(GetAnimationCount() <= index)
114   {
115     return false;
116   }
117
118   mAnimationArray[index].Play();
119   return true;
120 }
121
122 bool Scene3dView::PlayAnimations()
123 {
124   for(auto&& animation : mAnimationArray)
125   {
126     animation.Play();
127   }
128
129   return true;
130 }
131
132 bool Scene3dView::SetLight(Toolkit::Scene3dView::LightType type, Vector3 lightVector, Vector3 lightColor)
133 {
134   mLightType = type;
135   mLightVector = lightVector;
136   mLightColor  = lightColor;
137
138   for(auto&& shader : mShaderArray)
139   {
140     float hasLightSource = static_cast<float>(!!(GetLightType() & (Toolkit::Scene3dView::LightType::POINT_LIGHT | Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT)));
141     float isPointLight = static_cast<float>(!!(GetLightType() & Toolkit::Scene3dView::LightType::POINT_LIGHT));
142     shader.RegisterProperty("uHasLightSource", hasLightSource);
143     shader.RegisterProperty("uIsPointLight", isPointLight);
144     shader.RegisterProperty("uLightVector", lightVector);
145     shader.RegisterProperty("uLightColor", lightColor);
146   }
147
148   return true;
149 }
150
151 uint8_t* Scene3dView::GetCroppedBuffer(uint8_t* sourceBuffer, uint32_t bytesPerPixel, uint32_t width, uint32_t height, uint32_t xOffset, uint32_t yOffset, uint32_t xFaceSize, uint32_t yFaceSize)
152 {
153   uint32_t byteSize   = bytesPerPixel * xFaceSize * yFaceSize;
154   uint8_t* destBuffer = reinterpret_cast<uint8_t*>(malloc(byteSize + 4u));
155
156   int32_t srcStride  = width * bytesPerPixel;
157   int32_t destStride = xFaceSize * bytesPerPixel;
158   int32_t srcOffset  = xOffset * bytesPerPixel + yOffset * srcStride;
159   int32_t destOffset = 0;
160   for(uint16_t row = yOffset; row < yOffset + yFaceSize; ++row)
161   {
162     memcpy(destBuffer + destOffset, sourceBuffer + srcOffset, destStride);
163     srcOffset += srcStride;
164     destOffset += destStride;
165   }
166
167   return destBuffer;
168 }
169
170 void Scene3dView::UploadTextureFace(Texture& texture, Devel::PixelBuffer pixelBuffer, uint32_t faceIndex)
171 {
172   uint8_t* imageBuffer   = pixelBuffer.GetBuffer();
173   uint32_t bytesPerPixel = Pixel::GetBytesPerPixel(pixelBuffer.GetPixelFormat());
174   uint32_t imageWidth    = pixelBuffer.GetWidth();
175   uint32_t imageHeight   = pixelBuffer.GetHeight();
176
177   CubeType cubeType = (imageWidth / 4 == imageHeight / 3) ? CROSS_HORIZONTAL : ((imageWidth / 6 == imageHeight) ? ARRAY_HORIZONTAL : NONE);
178
179   uint32_t faceSize = 0;
180   if(cubeType == CROSS_HORIZONTAL)
181   {
182     faceSize = imageWidth / 4;
183   }
184   else if(cubeType == ARRAY_HORIZONTAL)
185   {
186     faceSize = imageWidth / 6;
187   }
188   else
189   {
190     return;
191   }
192
193   uint32_t xOffset = CUBEMAP_INDEX_X[cubeType][faceIndex] * faceSize;
194   uint32_t yOffset = CUBEMAP_INDEX_Y[cubeType][faceIndex] * faceSize;
195
196   uint8_t*  tempImageBuffer = GetCroppedBuffer(imageBuffer, bytesPerPixel, imageWidth, imageHeight, xOffset, yOffset, faceSize, faceSize);
197   PixelData pixelData       = PixelData::New(tempImageBuffer, faceSize * faceSize * bytesPerPixel, faceSize, faceSize, pixelBuffer.GetPixelFormat(), PixelData::FREE);
198   texture.Upload(pixelData, CubeMapLayer::POSITIVE_X + faceIndex, 0, 0, 0, faceSize, faceSize);
199 }
200
201 void Scene3dView::SetCubeMap(const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor)
202 {
203   // BRDF texture
204   const std::string imageDirPath = AssetManager::GetDaliImagePath();
205   const std::string imageBrdfUrl = imageDirPath + IMAGE_BRDF_FILE_NAME;
206   mBRDFTexture                   = LoadTexture(imageBrdfUrl.c_str(), true);
207   if(!mBRDFTexture)
208   {
209     return;
210   }
211
212   // Diffuse Cube Map
213   Devel::PixelBuffer diffusePixelBuffer = LoadImageFromFile(diffuseTexturePath);
214   uint32_t           diffuseFaceSize    = diffusePixelBuffer.GetWidth() / 4;
215   mDiffuseTexture                       = Texture::New(TextureType::TEXTURE_CUBE, diffusePixelBuffer.GetPixelFormat(), diffuseFaceSize, diffuseFaceSize);
216   for(uint32_t i = 0; i < 6; ++i)
217   {
218     UploadTextureFace(mDiffuseTexture, diffusePixelBuffer, i);
219   }
220   mDiffuseTexture.GenerateMipmaps();
221
222   // Specular Cube Map
223   Devel::PixelBuffer specularPixelBuffer = LoadImageFromFile(specularTexturePath);
224   uint32_t           specularFaceSize    = specularPixelBuffer.GetWidth() / 4;
225   mSpecularTexture                       = Texture::New(TextureType::TEXTURE_CUBE, specularPixelBuffer.GetPixelFormat(), specularFaceSize, specularFaceSize);
226   for(uint32_t i = 0; i < 6; ++i)
227   {
228     UploadTextureFace(mSpecularTexture, specularPixelBuffer, i);
229   }
230   mSpecularTexture.GenerateMipmaps();
231
232   mIBLScaleFactor = scaleFactor;
233   mUseIBL = true;
234 }
235
236 bool Scene3dView::SetDefaultCamera(const Dali::Camera::Type type, const float nearPlane, const Vector3 cameraPosition)
237 {
238   mDefaultCamera.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
239   mDefaultCamera.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
240   mDefaultCamera.SetType(type);
241   mDefaultCamera.SetNearClippingPlane(nearPlane);
242   mDefaultCamera.SetProperty(Actor::Property::POSITION, cameraPosition);
243   return true;
244 }
245
246 void Scene3dView::AddCamera(CameraActor cameraActor)
247 {
248   mCameraActorArray.push_back(cameraActor);
249 }
250
251 void Scene3dView::AddAnimation(Animation animation)
252 {
253   mAnimationArray.push_back(animation);
254 }
255
256 void Scene3dView::AddShader(Shader shader)
257 {
258   mShaderArray.push_back(shader);
259 }
260
261 Actor Scene3dView::GetRoot()
262 {
263   return mRoot;
264 }
265
266 CameraActor Scene3dView::GetDefaultCamera()
267 {
268   return mDefaultCamera;
269 }
270
271 uint32_t Scene3dView::GetCameraCount()
272 {
273   return mCameraActorArray.size();
274 }
275
276 CameraActor Scene3dView::GetCamera(uint32_t cameraIndex)
277 {
278   CameraActor cameraActor;
279   if(cameraIndex >= mCameraActorArray.size())
280   {
281     return cameraActor;
282   }
283   cameraActor = mCameraActorArray[cameraIndex];
284   return cameraActor;
285 }
286
287 Toolkit::Scene3dView::LightType Scene3dView::GetLightType()
288 {
289   return mLightType;
290 }
291
292 Vector3 Scene3dView::GetLightVector()
293 {
294   return mLightVector;
295 }
296
297 Vector3 Scene3dView::GetLightColor()
298 {
299   return mLightColor;
300 }
301
302 Vector4 Scene3dView::GetIBLScaleFactor()
303 {
304   return mIBLScaleFactor;
305 }
306
307 Texture Scene3dView::GetBRDFTexture()
308 {
309   return mBRDFTexture;
310 }
311
312 Texture Scene3dView::GetSpecularTexture()
313 {
314   return mSpecularTexture;
315 }
316
317 bool Scene3dView::HasImageBasedLighting()
318 {
319   return mUseIBL;
320 }
321
322 Texture Scene3dView::GetDiffuseTexture()
323 {
324   return mDiffuseTexture;
325 }
326
327 Texture Scene3dView::LoadTexture(const char* imageUrl, bool generateMipmaps)
328 {
329   Texture texture;
330
331   Devel::PixelBuffer pixelBuffer = LoadImageFromFile(imageUrl);
332   if(pixelBuffer)
333   {
334     texture             = Texture::New(TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight());
335     PixelData pixelData = Devel::PixelBuffer::Convert(pixelBuffer);
336     texture.Upload(pixelData);
337
338     if(generateMipmaps)
339     {
340       texture.GenerateMipmaps();
341     }
342   }
343
344   return texture;
345 }
346
347 void Scene3dView::OnInitialize()
348 {
349   mRoot.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
350   mRoot.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
351
352   Layer layer = Layer::New();
353   layer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
354   layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
355   layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
356   layer.Add(mRoot);
357
358   Actor self = Self();
359   // Apply some default resizing rules.
360   self.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
361   self.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
362   self.Add(layer);
363
364   CreateScene();
365 }
366
367 } //namespace Internal
368
369 } //namespace Toolkit
370
371 } //namespace Dali