X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-scene3d%2Finternal%2Fcontrols%2Fscene-view%2Fscene-view-impl.cpp;h=8c9b9b3c07ed5695c292b0bf1b5943134063f0b5;hb=HEAD;hp=bb44ab7edbab55fdb59ed962beecadc19a99abd9;hpb=9660fccbe1c9b4a902a236eeb5b2988b94c64c1d;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp index bb44ab7..efd89a7 100644 --- a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,20 +26,22 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include -#include #include // INTERNAL INCLUDES +#include #include #include -#include +#include using namespace Dali; @@ -58,14 +60,23 @@ BaseHandle Create() // Setup properties, signals and actions using the type-registry. DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create); +DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "AlphaMaskUrl", STRING, ALPHA_MASK_URL) +DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "MaskContentScale", FLOAT, MASK_CONTENT_SCALE) +DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "CropToMask", BOOLEAN, CROP_TO_MASK) DALI_TYPE_REGISTRATION_END() -Property::Index RENDERING_BUFFER = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1; -constexpr int32_t DEFAULT_ORIENTATION = 0; +Property::Index RENDERING_BUFFER = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1; +constexpr int32_t DEFAULT_ORIENTATION = 0; +constexpr int32_t INVALID_INDEX = -1; +constexpr int32_t INVALID_CAPTURE_ID = -1; +constexpr uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048; -constexpr uint8_t DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL = 4u; +constexpr int32_t SCENE_ORDER_INDEX = 100; +constexpr int32_t SHADOW_ORDER_INDEX = 99; static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity"; +static constexpr std::string_view Y_FLIP_MASK_TEXTURE = "uYFlipMaskTexture"; +static constexpr float FLIP_MASK_TEXTURE = 1.0f; Dali::Actor CreateSkybox() { @@ -130,7 +141,7 @@ Dali::Actor CreateSkybox() skyboxGeometry.AddVertexBuffer(vertexBuffer); skyboxGeometry.SetType(Geometry::TRIANGLES); - Dali::Shader shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data()); + Dali::Shader shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_CUBE"); Dali::Renderer skyboxRenderer; skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox); skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f); @@ -147,6 +158,145 @@ Dali::Actor CreateSkybox() return skyboxActor; } +void SetShadowLightConstraint(Dali::CameraActor selectedCamera, Dali::CameraActor shadowLightCamera) +{ + shadowLightCamera.SetProperty(Dali::CameraActor::Property::ASPECT_RATIO, 1.0f); + shadowLightCamera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 1.0f); + shadowLightCamera.SetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE, 0.5f); + shadowLightCamera.SetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE, 3.5f); + + //< Make constraint for above properties. + shadowLightCamera.RemoveConstraints(); + + // Compute ViewProjectionMatrix and store it to "tempViewProjectionMatrix" property + auto tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY); + Constraint projectionMatrixConstraint = Constraint::New(shadowLightCamera, tempViewProjectionMatrixIndex, [](Matrix& output, const PropertyInputContainer& inputs) + { + Matrix worldMatrix = inputs[0]->GetMatrix(); + float tangentFov_2 = tanf(inputs[4]->GetFloat()); + float nearDistance = inputs[5]->GetFloat(); + float farDistance = inputs[6]->GetFloat(); + float aspectRatio = inputs[7]->GetFloat(); + float nearY = 0.0f; + float nearX = 0.0f; + float farY = 0.0f; + float farX = 0.0f; + if(inputs[1]->GetInteger() == Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION) + { + if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL) + { + nearY = tangentFov_2 * nearDistance; + nearX = nearY * aspectRatio; + farY = tangentFov_2 * farDistance; + farX = farY * aspectRatio; + } + else + { + nearX = tangentFov_2 * nearDistance; + nearY = nearX / aspectRatio; + farX = tangentFov_2 * farDistance; + farY = farX / aspectRatio; + } + } + else + { + if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL) + { + nearY = inputs[3]->GetFloat(); + nearX = nearY * aspectRatio; + } + else + { + nearX = inputs[3]->GetFloat(); + nearY = nearX / aspectRatio; + } + farX = nearX; + farY = nearY; + } + + std::vector points; + points.push_back(Vector4(nearX, nearY, nearDistance, 1.0f)); + points.push_back(Vector4(-nearX, nearY, nearDistance, 1.0f)); + points.push_back(Vector4(-nearX, -nearY, nearDistance, 1.0f)); + points.push_back(Vector4(nearX, -nearY, nearDistance, 1.0f)); + points.push_back(Vector4(farX, farY, farDistance, 1.0f)); + points.push_back(Vector4(-farX, farY, farDistance, 1.0f)); + points.push_back(Vector4(-farX, -farY, farDistance, 1.0f)); + points.push_back(Vector4(farX, -farY, farDistance, 1.0f)); + + Matrix shadowCameraWorldMatrix = inputs[8]->GetMatrix(); + Vector4 worldCenter; + for(auto&& point : points) + { + point = worldMatrix * point; + worldCenter += point; + } + worldCenter /= 8.0f; + shadowCameraWorldMatrix.SetTranslation(Vector3(worldCenter)); + Matrix shadowCameraViewMatrix = shadowCameraWorldMatrix; + shadowCameraViewMatrix.Invert(); + + Vector3 areaMin = Vector3::ONE * MAXFLOAT, areaMax = Vector3::ONE * -MAXFLOAT; + for(auto&& point : points) + { + Vector4 pointV = shadowCameraViewMatrix * point; + areaMin.x = std::min(areaMin.x, pointV.x); + areaMin.y = std::min(areaMin.y, pointV.y); + areaMin.z = std::min(areaMin.z, pointV.z); + areaMax.x = std::max(areaMax.x, pointV.x); + areaMax.y = std::max(areaMax.y, pointV.y); + areaMax.z = std::max(areaMax.z, pointV.z); + } + + Vector2 center = Vector2(areaMax + areaMin) * 0.5; + float delta = std::max(std::abs(areaMax.x - areaMin.x), std::abs(areaMax.y - areaMin.y)); + float delta_2 = delta * 0.5f; + Vector2 squareAreaMin = center - Vector2::ONE * delta_2; + Vector2 squareAreaMax = center + Vector2::ONE * delta_2; + float deltaZ = areaMax.z - areaMin.z; + + float right = -squareAreaMin.x; + float left = -squareAreaMax.x; + float top = squareAreaMin.y; + float bottom = squareAreaMax.y; + float near = areaMin.z; + float far = areaMax.z; + + float* projMatrix = output.AsFloat(); + + projMatrix[0] = -2.0f / delta; + projMatrix[1] = 0.0f; + projMatrix[2] = 0.0f; + projMatrix[3] = 0.0f; + + projMatrix[4] = 0.0f; + projMatrix[5] = -2.0f / delta; + projMatrix[6] = 0.0f; + projMatrix[7] = 0.0f; + + projMatrix[8] = 0.0f; + projMatrix[9] = 0.0f; + projMatrix[10] = 2.0f / deltaZ; + projMatrix[11] = 0.0f; + + projMatrix[12] = -(right + left) / delta; + projMatrix[13] = -(top + bottom) / delta; + projMatrix[14] = -(near + far) / deltaZ; + projMatrix[15] = 1.0f; + + output = output * shadowCameraViewMatrix; }); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::Actor::Property::WORLD_MATRIX}); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::PROJECTION_MODE}); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::PROJECTION_DIRECTION}); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE}); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FIELD_OF_VIEW}); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::NEAR_PLANE_DISTANCE}); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FAR_PLANE_DISTANCE}); + projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::ASPECT_RATIO}); + projectionMatrixConstraint.AddSource(Source{shadowLightCamera, Dali::Actor::Property::WORLD_MATRIX}); + projectionMatrixConstraint.ApplyPost(); +} + } // anonymous namespace SceneView::SceneView() @@ -154,7 +304,9 @@ SceneView::SceneView() mWindowOrientation(DEFAULT_ORIENTATION), mSkybox(), mSkyboxOrientation(Quaternion()), - mSkyboxIntensity(1.0f) + mSkyboxIntensity(1.0f), + mLightObservers(), + mShaderManager(new Scene3D::Loader::ShaderManager()) { } @@ -177,6 +329,9 @@ SceneView::~SceneView() Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); mSkyboxLoadTask.Reset(); } + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); } } @@ -276,26 +431,24 @@ void SceneView::SelectCamera(const std::string& name) UpdateCamera(GetCamera(name)); } -void SceneView::RegisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* item) +void SceneView::RegisterSceneItem(Scene3D::Internal::LightObserver* item) { if(item) { - item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor); - mItems.push_back(item); + item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels); + item->NotifyShadowMapTexture(mShadowTexture); + mLightObservers.PushBack(item); } } -void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* item) +void SceneView::UnregisterSceneItem(Scene3D::Internal::LightObserver* item) { if(item) { - for(uint32_t i = 0; i < mItems.size(); ++i) + auto iter = mLightObservers.Find(item); + if(iter != mLightObservers.End()) { - if(mItems[i] == item) - { - mItems.erase(mItems.begin() + i); - break; - } + mLightObservers.Erase(iter); } } } @@ -303,13 +456,13 @@ void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor) { bool needIblReset = false; - bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); + bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); if(mDiffuseIblUrl != diffuseUrl) { mDiffuseIblUrl = diffuseUrl; if(mDiffuseIblUrl.empty()) { - needIblReset = true; + needIblReset = true; } else { @@ -323,7 +476,7 @@ void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const st mSpecularIblUrl = specularUrl; if(mSpecularIblUrl.empty()) { - needIblReset = true; + needIblReset = true; } else { @@ -356,7 +509,11 @@ void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const st mDiffuseTexture.Reset(); mSpecularTexture.Reset(); + mSpecularMipmapLevels = 1u; NotifyImageBasedLightTextureChange(); + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); } else { @@ -366,8 +523,11 @@ void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const st { Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); mIblDiffuseLoadTask.Reset(); + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); } - mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete)); + mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete)); Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask); mIblDiffuseDirty = false; } @@ -378,8 +538,11 @@ void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const st { Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); mIblSpecularLoadTask.Reset(); + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); } - mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete)); + mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete)); Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask); mIblSpecularDirty = false; } @@ -393,14 +556,14 @@ void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const st // If diffuse and specular textures are already loaded, emits resource ready signal here. if(IsResourceReady()) { - Control::SetResourceReady(false); + Control::SetResourceReady(); } } void SceneView::SetImageBasedLightScaleFactor(float scaleFactor) { mIblScaleFactor = scaleFactor; - for(auto&& item : mItems) + for(auto&& item : mLightObservers) { if(item) { @@ -414,6 +577,151 @@ float SceneView::GetImageBasedLightScaleFactor() const return mIblScaleFactor; } +void SceneView::AddLight(Scene3D::Light light) +{ + bool enabled = mShaderManager->AddLight(light); + mLights.push_back(std::make_pair(light, enabled)); + + if(light.IsShadowEnabled()) + { + SetShadow(light); + } +} + +void SceneView::RemoveLight(Scene3D::Light light) +{ + mShaderManager->RemoveLight(light); + for(uint32_t i = 0; i < mLights.size(); ++i) + { + if(mLights[i].first == light) + { + mLights.erase(mLights.begin() + i); + break; + } + } + + if(mLights.size() > mShaderManager->GetLightCount()) + { + for(auto&& waitingLight : mLights) + { + if(waitingLight.second) + { + continue; + } + + waitingLight.second = mShaderManager->AddLight(waitingLight.first); + break; + } + } + + if(light == mShadowLight) + { + RemoveShadow(light); + } + + if(!mShadowLight) + { + for(auto&& lightEntity : mLights) + { + if(!lightEntity.second || !lightEntity.first.IsShadowEnabled()) + { + continue; + } + SetShadow(lightEntity.first); + break; + } + } +} + +void SceneView::SetShadow(Scene3D::Light light) +{ + if(!!mShadowLight) + { + return; + } + + auto foundLight = std::find_if(mLights.begin(), mLights.end(), [light](std::pair lightEntity) -> bool + { return (lightEntity.second && lightEntity.first == light); }); + + if(foundLight == mLights.end()) + { + return; + } + + mShadowLight = light; + + // Directional Light setting. + CameraActor lightCamera = GetImplementation(light).GetCamera(); + CameraActor selectedCamera = GetSelectedCamera(); + SetShadowLightConstraint(selectedCamera, lightCamera); + + // make framebuffer for depth map and set it to render task. + uint32_t shadowMapBufferSize = std::min(std::max(GetResolutionWidth(), GetResolutionHeight()), MAXIMUM_SIZE_SHADOW_MAP); + UpdateShadowMapBuffer(shadowMapBufferSize); + + // use lightCamera as a camera of shadow render task. + if(mShadowMapRenderTask) + { + mShadowMapRenderTask.SetCameraActor(lightCamera); + } + + mShaderManager->SetShadow(light); + UpdateShadowMapBuffer(shadowMapBufferSize); +} + +void SceneView::RemoveShadow(Scene3D::Light light) +{ + if(mShadowLight != light) + { + return; + } + + // remove all constraint from light camera + CameraActor lightCamera = GetImplementation(mShadowLight).GetCamera(); + lightCamera.RemoveConstraints(); + + // reset framebuffer and remove it from render task. + mShadowFrameBuffer.Reset(); + mShaderManager->RemoveShadow(); + if(mShadowMapRenderTask) + { + mShadowMapRenderTask.SetCameraActor(CameraActor()); + } + + mShadowLight.Reset(); + + mShadowTexture.Reset(); + for(auto&& item : mLightObservers) + { + if(item) + { + item->NotifyShadowMapTexture(mShadowTexture); + } + } + + for(auto&& lightEntity : mLights) + { + if(!lightEntity.second || !lightEntity.first.IsShadowEnabled()) + { + continue; + } + SetShadow(lightEntity.first); + break; + } + + if(mSceneHolder && mShadowMapRenderTask) + { + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); + taskList.RemoveTask(mShadowMapRenderTask); + mShadowMapRenderTask.Reset(); + } +} + +uint32_t SceneView::GetActivatedLightCount() const +{ + return mShaderManager->GetLightCount(); +} + void SceneView::UseFramebuffer(bool useFramebuffer) { if(mUseFrameBuffer != useFramebuffer) @@ -428,62 +736,80 @@ bool SceneView::IsUsingFramebuffer() const return mUseFrameBuffer; } -void SceneView::SetSkybox(const std::string& skyboxUrl, Scene3D::SceneView::SkyboxType skyboxType) +void SceneView::SetResolution(uint32_t width, uint32_t height) { - mSkyboxEnvironmentMapType = skyboxType; - bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); - if(mSkyboxUrl != skyboxUrl) + if(mWindowWidth != width || mWindowHeight != height) { - mSkyboxDirty = true; - mSkyboxResourceReady = false; - mSkyboxUrl = skyboxUrl; + mWindowWidth = width; + mWindowHeight = height; + if(mUseFrameBuffer) + { + mWindowSizeChanged = true; + UpdateRenderTask(); + } } +} - if(mSkyboxUrl.empty()) +uint32_t SceneView::GetResolutionWidth() +{ + if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u) { - if(mSkyboxLoadTask) - { - Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); - mSkyboxLoadTask.Reset(); - } - if(mSkyboxImageLoader) - { - mSkyboxImageLoader.Cancel(mSkyboxImageId); - } - mSkyboxDirty = false; - mSkyboxResourceReady = true; + return static_cast(Self().GetProperty(Dali::Actor::Property::SIZE_WIDTH)); } - else + return mWindowWidth; +} + +uint32_t SceneView::GetResolutionHeight() +{ + if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u) { - if(isOnScene && mSkyboxDirty) + return static_cast(Self().GetProperty(Dali::Actor::Property::SIZE_HEIGHT)); + } + return mWindowHeight; +} + +void SceneView::ResetResolution() +{ + SetResolution(0u, 0u); +} + +void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel) +{ + if(mFrameBufferMultiSamplingLevel != multiSamplingLevel) + { + mFrameBufferMultiSamplingLevel = multiSamplingLevel; + + // Create new framebuffer with changed multiSamplingLevel. + if(mRenderTask && mFrameBuffer && mTexture) { - if(mSkyboxLoadTask) - { - Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); - mSkyboxLoadTask.Reset(); - } - if(mSkyboxImageLoader) - { - mSkyboxImageLoader.Cancel(mSkyboxImageId); - } - if(mSkyboxEnvironmentMapType == Scene3D::SceneView::SkyboxType::CUBEMAP) - { - mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, MakeCallback(this, &SceneView::OnSkyboxLoadComplete)); - Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask); - } - else - { - mSkyboxImageLoader = Dali::Toolkit::AsyncImageLoader::New(); - mSkyboxImageLoader.ImageLoadedSignal().Connect(this, &SceneView::OnSkyboxEquirectangularLoadComplete); - mSkyboxImageId = mSkyboxImageLoader.Load(mSkyboxUrl); - } - mSkyboxDirty = false; + mFrameBuffer = FrameBuffer::New(GetResolutionWidth(), GetResolutionHeight(), FrameBuffer::Attachment::DEPTH_STENCIL); + mFrameBuffer.AttachColorTexture(mTexture); + DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel); + mRenderTask.SetFrameBuffer(mFrameBuffer); + + // Note : we don't need to create new visual since visual's url is depend on mTexture. } } +} - if(IsResourceReady()) +uint8_t SceneView::GetFramebufferMultiSamplingLevel() const +{ + return mFrameBufferMultiSamplingLevel; +} + +void SceneView::SetSkybox(const std::string& skyboxUrl) +{ + if(mSkyboxUrl != skyboxUrl) + { + UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType); + } +} + +void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType) +{ + if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType) { - Control::SetResourceReady(false); + UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType); } } @@ -521,6 +847,222 @@ Quaternion SceneView::GetSkyboxOrientation() const return mSkyboxOrientation; } +int32_t SceneView::Capture(Dali::CameraActor camera, const Vector2& size) +{ + if(size.x <= 0.0f || size.y <= 0.0f) + { + DALI_LOG_ERROR("The width and height should be positive.\n"); + return INVALID_CAPTURE_ID; + } + + uint32_t width = unsigned(size.width); + uint32_t height = unsigned(size.height); + if(width > Dali::GetMaxTextureSize() || height > Dali::GetMaxTextureSize()) + { + DALI_LOG_ERROR("The input size is too large.\n"); + return INVALID_CAPTURE_ID; + } + + if(!mRootLayer.GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE)) + { + DALI_LOG_ERROR("Current SceneView is not connected on scene tree\n"); + return INVALID_CAPTURE_ID; + } + + if(!camera.GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE)) + { + mRootLayer.Add(camera); + } + + std::shared_ptr captureData = std::make_shared(); + captureData->mCaptureId = mCaptureId; + captureData->mCaptureTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height); + captureData->mCaptureFrameBuffer = Dali::FrameBuffer::New(captureData->mCaptureTexture.GetWidth(), captureData->mCaptureTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH_STENCIL); + DevelFrameBuffer::SetMultiSamplingLevel(captureData->mCaptureFrameBuffer, mFrameBufferMultiSamplingLevel); + captureData->mCaptureFrameBuffer.AttachColorTexture(captureData->mCaptureTexture); + + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); + captureData->mCaptureTask = taskList.CreateTask(); + captureData->mCaptureTask.SetSourceActor(mRootLayer); + captureData->mCaptureTask.SetExclusive(true); + captureData->mCaptureTask.SetCullMode(false); + captureData->mCaptureTask.SetOrderIndex(SCENE_ORDER_INDEX + 1); + captureData->mCaptureTask.SetCameraActor(camera); + captureData->mCaptureTask.SetFrameBuffer(captureData->mCaptureFrameBuffer); + captureData->mCaptureTask.SetClearEnabled(true); + captureData->mCaptureTask.SetClearColor(Color::TRANSPARENT); + captureData->mCaptureTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE); + + captureData->mCaptureInvertCamera = Dali::CameraActor::New(size); + captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT); + captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::POSITION_X, size.x / 2.0f); + captureData->mCaptureInvertCamera.SetProperty(Dali::Actor::Property::POSITION_Y, size.y / 2.0f); + + captureData->mCaptureUrl = Dali::Toolkit::Image::GenerateUrl(captureData->mCaptureFrameBuffer, 0u); + captureData->mCaptureImageView = Dali::Toolkit::ImageView::New(captureData->mCaptureUrl.GetUrl()); + captureData->mCaptureImageView.SetProperty(Dali::Actor::Property::SIZE, size); + captureData->mCaptureImageView.Add(captureData->mCaptureInvertCamera); + + Window window = DevelWindow::Get(Self()); + window.Add(captureData->mCaptureImageView); + + captureData->mCaptureInvertTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height); + captureData->mCaptureInvertFrameBuffer = Dali::FrameBuffer::New(captureData->mCaptureInvertTexture.GetWidth(), captureData->mCaptureInvertTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH_STENCIL); + captureData->mCaptureInvertFrameBuffer.AttachColorTexture(captureData->mCaptureInvertTexture); + + captureData->mCaptureInvertTask = taskList.CreateTask(); + captureData->mCaptureInvertTask.SetSourceActor(captureData->mCaptureImageView); + captureData->mCaptureInvertTask.SetExclusive(true); + captureData->mCaptureInvertTask.SetCullMode(false); + captureData->mCaptureInvertTask.SetOrderIndex(SCENE_ORDER_INDEX + 2); + captureData->mCaptureInvertTask.SetCameraActor(captureData->mCaptureInvertCamera); + captureData->mCaptureInvertTask.SetFrameBuffer(captureData->mCaptureInvertFrameBuffer); + captureData->mCaptureInvertTask.SetClearEnabled(true); + captureData->mCaptureInvertTask.SetClearColor(Color::TRANSPARENT); + captureData->mCaptureInvertTask.SetRefreshRate(Dali::RenderTask::REFRESH_ONCE); + captureData->mCaptureInvertTask.FinishedSignal().Connect(this, &SceneView::OnCaptureFinished); + + captureData->mStartTick = mTimerTickCount; + + mCaptureContainer.push_back(std::make_pair(captureData->mCaptureInvertTask, captureData)); + + if(!mCaptureTimer) + { + mCaptureTimer = Dali::Timer::New(1000); + mCaptureTimer.TickSignal().Connect(this, &SceneView::OnTimeOut); + mCaptureTimer.Start(); + } + return mCaptureId++; +} + +Dali::Scene3D::SceneView::CaptureFinishedSignalType& SceneView::CaptureFinishedSignal() +{ + return mCaptureFinishedSignal; +} + +Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const +{ + return mShaderManager; +} + +void SceneView::UpdateShadowUniform(Scene3D::Light light) +{ + mShaderManager->UpdateShadowUniform(light); +} + +void SceneView::SetAlphaMaskUrl(std::string& alphaMaskUrl) +{ + if(mAlphaMaskUrl != alphaMaskUrl) + { + mAlphaMaskUrl = alphaMaskUrl; + mMaskingPropertyChanged = true; + UpdateRenderTask(); + } +} + +std::string SceneView::GetAlphaMaskUrl() +{ + return mAlphaMaskUrl; +} + +void SceneView::SetMaskContentScaleFactor(float maskContentScaleFactor) +{ + if(mMaskContentScaleFactor != maskContentScaleFactor) + { + mMaskContentScaleFactor = maskContentScaleFactor; + mMaskingPropertyChanged = true; + UpdateRenderTask(); + } +} + +float SceneView::GetMaskContentScaleFactor() +{ + return mMaskContentScaleFactor; +} + +void SceneView::EnableCropToMask(bool enableCropToMask) +{ + if(mCropToMask != enableCropToMask) + { + mCropToMask = enableCropToMask; + mMaskingPropertyChanged = true; + UpdateRenderTask(); + } +} + +bool SceneView::IsEnabledCropToMask() +{ + return mCropToMask; +} + +Dali::RenderTask SceneView::GetRenderTask() +{ + return mRenderTask; +} + +void SceneView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value) +{ + Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object)); + + if(sceneView) + { + SceneView& sceneViewImpl(GetImpl(sceneView)); + + switch(index) + { + case Scene3D::SceneView::Property::ALPHA_MASK_URL: + { + std::string alphaMaskUrl = value.Get(); + sceneViewImpl.SetAlphaMaskUrl(alphaMaskUrl); + break; + } + case Scene3D::SceneView::Property::MASK_CONTENT_SCALE: + { + sceneViewImpl.SetMaskContentScaleFactor(value.Get()); + break; + } + case Scene3D::SceneView::Property::CROP_TO_MASK: + { + sceneViewImpl.EnableCropToMask(value.Get()); + break; + } + } + } +} + +Property::Value SceneView::GetProperty(BaseObject* object, Property::Index index) +{ + Property::Value value; + + Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object)); + + if(sceneView) + { + SceneView& sceneViewImpl(GetImpl(sceneView)); + + switch(index) + { + case Scene3D::SceneView::Property::ALPHA_MASK_URL: + { + value = sceneViewImpl.GetAlphaMaskUrl(); + break; + } + case Scene3D::SceneView::Property::MASK_CONTENT_SCALE: + { + value = sceneViewImpl.GetMaskContentScaleFactor(); + break; + } + case Scene3D::SceneView::Property::CROP_TO_MASK: + { + value = sceneViewImpl.IsEnabledCropToMask(); + break; + } + } + } + return value; +} + /////////////////////////////////////////////////////////// // // Private methods @@ -536,23 +1078,33 @@ void SceneView::OnSceneConnection(int depth) if(!mSkyboxUrl.empty()) { - SetSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType); + UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType); } Window window = DevelWindow::Get(Self()); if(window) { + // Only for on-screen window window.ResizeSignal().Connect(this, &SceneView::OnWindowResized); - RenderTaskList taskList = window.GetRenderTaskList(); + + mWindow = window; + mWindowOrientation = DevelWindow::GetPhysicalOrientation(window); + } + + // On-screen / Off-screen window + mSceneHolder = Integration::SceneHolder::Get(Self()); + if(mSceneHolder) + { + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); mRenderTask = taskList.CreateTask(); mRenderTask.SetSourceActor(mRootLayer); mRenderTask.SetExclusive(true); mRenderTask.SetInputEnabled(true); mRenderTask.SetCullMode(false); + mRenderTask.SetOrderIndex(SCENE_ORDER_INDEX); mRenderTask.SetScreenToFrameBufferMappingActor(Self()); UpdateRenderTask(); - mWindow = window; } Control::OnSceneConnection(depth); @@ -560,20 +1112,66 @@ void SceneView::OnSceneConnection(int depth) void SceneView::OnSceneDisconnection() { - mItems.clear(); + mLightObservers.Clear(); Window window = mWindow.GetHandle(); if(window) { window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized); - RenderTaskList taskList = window.GetRenderTaskList(); + } + mWindow.Reset(); + + auto self = Self(); + Dali::Scene3D::SceneView handle(Dali::Scene3D::SceneView::DownCast(self)); + std::vector>> tempContainer(mCaptureContainer); + for(auto&& capture : tempContainer) + { + Dali::Scene3D::SceneView::CaptureResult result{capture.second->mCaptureId, Dali::Toolkit::ImageUrl(), Dali::Scene3D::SceneView::CaptureFinishState::FAILED}; + mCaptureFinishedSignal.Emit(handle, result); + } + tempContainer.clear(); + + for(auto && capture : mCaptureContainer) + { + if(mSceneHolder) + { + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); + taskList.RemoveTask(capture.second->mCaptureTask); + taskList.RemoveTask(capture.second->mCaptureInvertTask); + } + capture.second->mCaptureTask.Reset(); + capture.second->mCaptureInvertTask.Reset(); + capture.second->mCaptureTexture.Reset(); + capture.second->mCaptureInvertTexture.Reset(); + capture.second->mCaptureFrameBuffer.Reset(); + capture.second->mCaptureInvertFrameBuffer.Reset(); + capture.second->mCaptureUrl.Reset(); + capture.second->mCaptureImageView.Unparent(); + capture.second->mCaptureImageView.Reset(); + capture.second->mCaptureInvertCamera.Unparent(); + capture.second->mCaptureInvertCamera.Reset(); + } + mCaptureContainer.clear(); + + + if(mSceneHolder) + { if(mRenderTask) { + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); taskList.RemoveTask(mRenderTask); - mFrameBuffer.Reset(); + mRenderTask.Reset(); + } + if(mShadowMapRenderTask) + { + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); + taskList.RemoveTask(mShadowMapRenderTask); + mShadowMapRenderTask.Reset(); } + mSceneHolder.Reset(); } - mWindow.Reset(); + mFrameBuffer.Reset(); + mShadowFrameBuffer.Reset(); Control::OnSceneDisconnection(); } @@ -590,10 +1188,9 @@ void SceneView::OnInitialize() mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false); self.Add(mRootLayer); - mDefaultCamera = Dali::CameraActor::New(); + mDefaultCamera = Dali::CameraActor::New3DCamera(); mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); - mDefaultCamera.SetNearClippingPlane(1.0f); AddCamera(mDefaultCamera); UpdateCamera(mDefaultCamera); } @@ -651,6 +1248,10 @@ void SceneView::UpdateCamera(CameraActor camera) } mSelectedCamera = camera; + if(mShadowLight) + { + SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera()); + } UpdateRenderTask(); } @@ -662,50 +1263,56 @@ void SceneView::UpdateRenderTask() { mRenderTask.SetCameraActor(mSelectedCamera); } + uint32_t width = GetResolutionWidth(); + uint32_t height = GetResolutionHeight(); - Vector3 size = Self().GetProperty(Dali::Actor::Property::SIZE); - const float aspectRatio = size.width / size.height; - mSelectedCamera.SetAspectRatio(aspectRatio); + uint32_t shadowMapBufferSize = std::min(std::max(width, height), MAXIMUM_SIZE_SHADOW_MAP); + UpdateShadowMapBuffer(shadowMapBufferSize); if(mUseFrameBuffer) { Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer(); if(!currentFrameBuffer || - !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), size.width) || - !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), size.height)) + !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), width) || + !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), height) || + mMaskingPropertyChanged || + mWindowSizeChanged) { mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR); mRenderTask.ResetViewportGuideActor(); mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO)); // create offscreen buffer of new size to render our child actors to - mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height)); - mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL); + mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height); + mFrameBuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH_STENCIL); mFrameBuffer.AttachColorTexture(mTexture); - DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL); + DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel); Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u); Property::Map imagePropertyMap; imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE); imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl()); - // To make sure this visual call LoadTexture API immediate. - imagePropertyMap.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, Toolkit::ImageVisual::LoadPolicy::IMMEDIATE); - imagePropertyMap.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, Toolkit::ImageVisual::ReleasePolicy::DESTROYED); // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling. imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f)); - mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap); - - // Use premultiplied alpha when we use FBO - if(mVisual) + if(!mAlphaMaskUrl.empty()) { - Toolkit::GetImplementation(mVisual).EnablePreMultipliedAlpha(true); + imagePropertyMap.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl); + imagePropertyMap.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, true); + imagePropertyMap.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskContentScaleFactor); + imagePropertyMap.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mCropToMask); + imagePropertyMap.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, Toolkit::DevelImageVisual::MaskingType::MASKING_ON_RENDERING); + Self().RegisterProperty(Y_FLIP_MASK_TEXTURE, FLIP_MASK_TEXTURE); } + mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap); Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual); mRenderTask.SetFrameBuffer(mFrameBuffer); mRenderTask.SetClearEnabled(true); mRenderTask.SetClearColor(Color::TRANSPARENT); + + mMaskingPropertyChanged = false; + mWindowSizeChanged = false; } } else @@ -726,6 +1333,12 @@ void SceneView::UpdateRenderTask() } } + if(width > 0u && height > 0u) + { + float aspectRatio = static_cast(width) / static_cast(height); + mSelectedCamera.SetAspectRatio(aspectRatio); + } + RotateCamera(); } } @@ -748,11 +1361,61 @@ void SceneView::RotateCamera() } } -void SceneView::OnSkyboxEquirectangularLoadComplete(uint32_t loadedTaskId, PixelData pixelData) +void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType) { - mSkyboxTexture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight()); - mSkyboxTexture.Upload(pixelData, 0, 0, 0, 0, pixelData.GetWidth(), pixelData.GetHeight()); - OnSkyboxLoadComplete(); + bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); + if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType) + { + mSkyboxDirty = true; + mSkyboxResourceReady = false; + mSkyboxUrl = skyboxUrl; + mSkyboxEnvironmentMapType = skyboxEnvironmentMapType; + } + + if(mSkyboxUrl.empty()) + { + if(mSkyboxLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); + mSkyboxLoadTask.Reset(); + } + + if(mSkybox) + { + mSkybox.Unparent(); + mSkybox.Reset(); + mSkyboxTexture.Reset(); + } + + mSkyboxDirty = false; + mSkyboxResourceReady = true; + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); + } + else + { + if(isOnScene && mSkyboxDirty) + { + if(mSkyboxLoadTask) + { + Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); + mSkyboxLoadTask.Reset(); + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); + } + + mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete)); + Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask); + mSkyboxDirty = false; + } + } + + if(IsResourceReady()) + { + Control::SetResourceReady(); + } } void SceneView::OnSkyboxLoadComplete() @@ -769,22 +1432,15 @@ void SceneView::OnSkyboxLoadComplete() } mSkyboxResourceReady = true; - if(IsResourceReady()) - { - Control::SetResourceReady(false); - } - + mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture(); Shader skyboxShader; - if(mSkyboxEnvironmentMapType == Scene3D::SceneView::SkyboxType::CUBEMAP) + if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP) { - mSkyboxTexture = (mSkyboxLoadTask->HasSucceeded()) ? mSkyboxLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); - skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data()); - Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask); - mSkyboxLoadTask.Reset(); + skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_CUBE"); } else { - skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data()); + skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_EQUIRECTANGULAR"); } Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer(); @@ -795,28 +1451,36 @@ void SceneView::OnSkyboxLoadComplete() skyboxRenderer.SetTextures(skyboxTextures); skyboxRenderer.SetShader(skyboxShader); } + + mSkyboxLoadTask.Reset(); + + if(IsResourceReady()) + { + Control::SetResourceReady(); + } } void SceneView::OnIblDiffuseLoadComplete() { - mDiffuseTexture = (mIblDiffuseLoadTask->HasSucceeded()) ? mIblDiffuseLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); + mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture(); mIblDiffuseResourceReady = true; + mIblDiffuseLoadTask.Reset(); if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { OnIblLoadComplete(); } - mIblDiffuseLoadTask.Reset(); } void SceneView::OnIblSpecularLoadComplete() { - mSpecularTexture = (mIblSpecularLoadTask->HasSucceeded()) ? mIblSpecularLoadTask->GetEnvironmentMap().CreateTexture() : Texture(); + mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture(); + mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels(); mIblSpecularResourceReady = true; + mIblSpecularLoadTask.Reset(); if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { OnIblLoadComplete(); } - mIblSpecularLoadTask.Reset(); } void SceneView::OnIblLoadComplete() @@ -824,21 +1488,143 @@ void SceneView::OnIblLoadComplete() NotifyImageBasedLightTextureChange(); if(IsResourceReady()) { - Control::SetResourceReady(false); + Control::SetResourceReady(); } } void SceneView::NotifyImageBasedLightTextureChange() { - for(auto&& item : mItems) + for(auto&& item : mLightObservers) { if(item) { - item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor); + item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels); } } } +void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize) +{ + if(!mShadowLight || !mSceneHolder) + { + return; + } + + if(!mShadowMapRenderTask) + { + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); + mShadowMapRenderTask = taskList.CreateTask(); + mShadowMapRenderTask.SetSourceActor(mRootLayer); + mShadowMapRenderTask.SetExclusive(true); + mShadowMapRenderTask.SetInputEnabled(false); + mShadowMapRenderTask.SetCullMode(false); + mShadowMapRenderTask.SetClearEnabled(true); + mShadowMapRenderTask.SetClearColor(Color::WHITE); + mShadowMapRenderTask.SetRenderPassTag(10); + mShadowMapRenderTask.SetCameraActor(GetImplementation(mShadowLight).GetCamera()); + mShadowMapRenderTask.SetOrderIndex(SHADOW_ORDER_INDEX); + } + + Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer(); + if(!currentShadowFrameBuffer || + !mShadowTexture || + !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize)) + { + mShadowFrameBuffer.Reset(); + mShadowTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, shadowMapSize, shadowMapSize); + mShadowFrameBuffer = FrameBuffer::New(shadowMapSize, shadowMapSize, FrameBuffer::Attachment::NONE); + DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture); + mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer); + + for(auto&& item : mLightObservers) + { + if(item) + { + item->NotifyShadowMapTexture(mShadowTexture); + } + } + } +} + +void SceneView::OnCaptureFinished(Dali::RenderTask& task) +{ + int32_t captureId = INVALID_CAPTURE_ID; + Dali::Toolkit::ImageUrl imageUrl; + + auto iter = std::find_if(mCaptureContainer.begin(), mCaptureContainer.end(), [task](std::pair> item) + { return item.first == task; }); + + if(iter != mCaptureContainer.end()) + { + captureId = iter->second->mCaptureId; + imageUrl = Dali::Toolkit::ImageUrl::New(iter->second->mCaptureInvertTexture); + if(mSceneHolder) + { + RenderTaskList taskList = mSceneHolder.GetRenderTaskList(); + taskList.RemoveTask(iter->second->mCaptureTask); + taskList.RemoveTask(iter->second->mCaptureInvertTask); + } + iter->second->mCaptureTexture.Reset(); + iter->second->mCaptureInvertTexture.Reset(); + iter->second->mCaptureFrameBuffer.Reset(); + iter->second->mCaptureInvertFrameBuffer.Reset(); + iter->second->mCaptureUrl.Reset(); + iter->second->mCaptureImageView.Unparent(); + iter->second->mCaptureImageView.Reset(); + mCaptureContainer.erase(iter); + + auto self = Self(); + Dali::Scene3D::SceneView handle(Dali::Scene3D::SceneView::DownCast(self)); + + Dali::Scene3D::SceneView::CaptureResult result{captureId, imageUrl, Dali::Scene3D::SceneView::CaptureFinishState::SUCCEEDED}; + mCaptureFinishedSignal.Emit(handle, result); + } + + if(mCaptureContainer.empty() && mCaptureTimer) + { + mCaptureTimer.Stop(); + mCaptureTimer.Reset(); + mTimerTickCount = 0; + } +} + +bool SceneView::OnTimeOut() +{ + mTimerTickCount++; + auto self = Self(); + Dali::Scene3D::SceneView handle(Dali::Scene3D::SceneView::DownCast(self)); + std::vector>> tempContainer; + for(auto&& capture : mCaptureContainer) + { + if(capture.second->mStartTick + 1 < mTimerTickCount) + { + tempContainer.push_back(capture); + } + } + + for(auto&& capture : tempContainer) + { + Dali::Scene3D::SceneView::CaptureResult result{capture.second->mCaptureId, Dali::Toolkit::ImageUrl(), Dali::Scene3D::SceneView::CaptureFinishState::FAILED}; + mCaptureFinishedSignal.Emit(handle, result); + } + + int32_t tickCount = mTimerTickCount; + auto it = std::remove_if(mCaptureContainer.begin(), mCaptureContainer.end(), [tickCount](std::pair> item) { + return item.second->mStartTick + 1 < tickCount; + }); + mCaptureContainer.erase(it, mCaptureContainer.end()); + mCaptureContainer.shrink_to_fit(); + + if(mCaptureContainer.empty() && mCaptureTimer) + { + mCaptureTimer.Stop(); + mCaptureTimer.Reset(); + mTimerTickCount = 0; + } + + return !mCaptureContainer.empty(); +} + } // namespace Internal } // namespace Scene3D } // namespace Dali