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