/*
- * Copyright (c) 2023 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.
#include <string_view>
// INTERNAL INCLUDES
+#include <dali-scene3d/internal/common/image-resource-loader.h>
#include <dali-scene3d/internal/controls/model/model-impl.h>
#include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
#include <dali-scene3d/internal/light/light-impl.h>
+#include <dali/integration-api/debug.h>
+
using namespace Dali;
namespace Dali
// 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;
-constexpr int32_t INVALID_INDEX = -1;
+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 uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048;
+
+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()
{
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);
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<Matrix>(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<Vector4> 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()
mWindowOrientation(DEFAULT_ORIENTATION),
mSkybox(),
mSkyboxOrientation(Quaternion()),
- mSkyboxIntensity(1.0f)
+ mSkyboxIntensity(1.0f),
+ mLightObservers(),
+ mShaderManager(new Scene3D::Loader::ShaderManager())
{
}
Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
mSkyboxLoadTask.Reset();
}
+
+ // Request image resource GC
+ Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
}
}
if(item)
{
item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
-
- if(mActivatedLightCount > 0)
- {
- uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- for(uint32_t i = 0; i < maxLightCount; ++i)
- {
- if(mActivatedLights[i])
- {
- item->NotifyLightAdded(i, mActivatedLights[i]);
- }
- }
- }
- mItems.push_back(item);
+ item->NotifyShadowMapTexture(mShadowTexture);
+ mLightObservers.PushBack(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)
- {
- if(mActivatedLightCount > 0)
- {
- uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- for(uint32_t i = 0; i < maxLightCount; ++i)
- {
- if(mActivatedLights[i])
- {
- item->NotifyLightRemoved(i);
- }
- }
- }
- mItems.erase(mItems.begin() + i);
- break;
- }
+ mLightObservers.Erase(iter);
}
}
}
mSpecularMipmapLevels = 1u;
NotifyImageBasedLightTextureChange();
+
+ // Request image resource GC
+ Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
}
else
{
{
Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
mIblDiffuseLoadTask.Reset();
+
+ // Request image resource GC
+ Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
}
mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
{
Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
mIblSpecularLoadTask.Reset();
+
+ // Request image resource GC
+ Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
}
mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
{
mIblScaleFactor = scaleFactor;
- for(auto&& item : mItems)
+ for(auto&& item : mLightObservers)
{
if(item)
{
void SceneView::AddLight(Scene3D::Light light)
{
- bool enabled = AddLightInternal(light);
+ bool enabled = mShaderManager->AddLight(light);
mLights.push_back(std::make_pair(light, enabled));
-}
-void SceneView::RemoveLight(Scene3D::Light light)
-{
- if(mActivatedLights.empty())
+ if(light.IsShadowEnabled())
{
- return;
+ SetShadow(light);
}
+}
- bool needToDisable = false;
+void SceneView::RemoveLight(Scene3D::Light light)
+{
+ mShaderManager->RemoveLight(light);
for(uint32_t i = 0; i < mLights.size(); ++i)
{
if(mLights[i].first == light)
{
- // If mLights[i].second is true, it means the light is currently activated in Scene.
- // Then it should be removed from mActivatedLights list too.
- needToDisable = mLights[i].second;
mLights.erase(mLights.begin() + i);
break;
}
}
- uint32_t maxNumberOfLight = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- if(needToDisable)
+ if(mLights.size() > mShaderManager->GetLightCount())
{
- uint32_t removedIndex = RemoveLightInternal(light);
- if(mActivatedLightCount < maxNumberOfLight && mLights.size() >= maxNumberOfLight)
+ for(auto&& waitingLight : mLights)
{
- for(auto && lightItem : mLights)
+ if(waitingLight.second)
{
- if(lightItem.second == false)
- {
- lightItem.second = AddLightInternal(lightItem.first);
- break;
- }
+ 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<Scene3D::Light, bool> 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);
}
+ }
- // To remove empty entity of mActivatedLights, moves last object to empty position.
- // Because one Light is removed, mActivatedLights[mActivatedLightCount] is current last object of the list.
- if(!mActivatedLights[removedIndex] && mActivatedLightCount > 0 && removedIndex < mActivatedLightCount)
+ for(auto&& lightEntity : mLights)
+ {
+ if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
{
- Scene3D::Light reorderingLight = mActivatedLights[mActivatedLightCount];
- RemoveLightInternal(reorderingLight);
- AddLightInternal(reorderingLight);
+ continue;
}
+ SetShadow(lightEntity.first);
+ break;
+ }
+
+ if(mSceneHolder && mShadowMapRenderTask)
+ {
+ RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
+ taskList.RemoveTask(mShadowMapRenderTask);
+ mShadowMapRenderTask.Reset();
}
}
uint32_t SceneView::GetActivatedLightCount() const
{
- return mActivatedLightCount;
+ return mShaderManager->GetLightCount();
}
void SceneView::UseFramebuffer(bool useFramebuffer)
return mUseFrameBuffer;
}
+void SceneView::SetResolution(uint32_t width, uint32_t height)
+{
+ if(mWindowWidth != width || mWindowHeight != height)
+ {
+ mWindowWidth = width;
+ mWindowHeight = height;
+ if(mUseFrameBuffer)
+ {
+ mWindowSizeChanged = true;
+ UpdateRenderTask();
+ }
+ }
+}
+
+uint32_t SceneView::GetResolutionWidth()
+{
+ if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
+ {
+ return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_WIDTH));
+ }
+ return mWindowWidth;
+}
+
+uint32_t SceneView::GetResolutionHeight()
+{
+ if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
+ {
+ return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_HEIGHT));
+ }
+ return mWindowHeight;
+}
+
+void SceneView::ResetResolution()
+{
+ SetResolution(0u, 0u);
+}
+
void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel)
{
if(mFrameBufferMultiSamplingLevel != multiSamplingLevel)
// Create new framebuffer with changed multiSamplingLevel.
if(mRenderTask && mFrameBuffer && mTexture)
{
- Vector3 size = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
-
- mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
+ mFrameBuffer = FrameBuffer::New(GetResolutionWidth(), GetResolutionHeight(), FrameBuffer::Attachment::DEPTH_STENCIL);
mFrameBuffer.AttachColorTexture(mTexture);
DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
mRenderTask.SetFrameBuffer(mFrameBuffer);
return mSkyboxOrientation;
}
+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<std::string>();
+ sceneViewImpl.SetAlphaMaskUrl(alphaMaskUrl);
+ break;
+ }
+ case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
+ {
+ sceneViewImpl.SetMaskContentScaleFactor(value.Get<float>());
+ break;
+ }
+ case Scene3D::SceneView::Property::CROP_TO_MASK:
+ {
+ sceneViewImpl.EnableCropToMask(value.Get<bool>());
+ 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
mRenderTask.SetExclusive(true);
mRenderTask.SetInputEnabled(true);
mRenderTask.SetCullMode(false);
+ mRenderTask.SetOrderIndex(SCENE_ORDER_INDEX);
mRenderTask.SetScreenToFrameBufferMappingActor(Self());
UpdateRenderTask();
void SceneView::OnSceneDisconnection()
{
- mItems.clear();
+ mLightObservers.Clear();
Window window = mWindow.GetHandle();
if(window)
taskList.RemoveTask(mRenderTask);
mRenderTask.Reset();
}
+ if(mShadowMapRenderTask)
+ {
+ RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
+ taskList.RemoveTask(mShadowMapRenderTask);
+ mShadowMapRenderTask.Reset();
+ }
mSceneHolder.Reset();
}
mFrameBuffer.Reset();
+ mShadowFrameBuffer.Reset();
Control::OnSceneDisconnection();
}
}
mSelectedCamera = camera;
+ if(mShadowLight)
+ {
+ SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera());
+ }
UpdateRenderTask();
}
{
mRenderTask.SetCameraActor(mSelectedCamera);
}
+ uint32_t width = GetResolutionWidth();
+ uint32_t height = GetResolutionHeight();
- Vector3 size = Self().GetProperty<Vector3>(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, mFrameBufferMultiSamplingLevel);
Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
// 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);
+ if(!mAlphaMaskUrl.empty())
+ {
+ 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
}
}
+ if(width > 0u && height > 0u)
+ {
+ float aspectRatio = static_cast<float>(width) / static_cast<float>(height);
+ mSelectedCamera.SetAspectRatio(aspectRatio);
+ }
+
RotateCamera();
}
}
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
{
{
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));
}
mSkyboxResourceReady = true;
- if(IsResourceReady())
- {
- Control::SetResourceReady();
- }
-
- mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture();
+ mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture();
Shader skyboxShader;
if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP)
{
- skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
+ 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();
}
mSkyboxLoadTask.Reset();
+
+ if(IsResourceReady())
+ {
+ Control::SetResourceReady();
+ }
}
void SceneView::OnIblDiffuseLoadComplete()
{
mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
mIblDiffuseResourceReady = true;
+ mIblDiffuseLoadTask.Reset();
if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
{
OnIblLoadComplete();
}
- mIblDiffuseLoadTask.Reset();
}
void SceneView::OnIblSpecularLoadComplete()
mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
mIblSpecularResourceReady = true;
+ mIblSpecularLoadTask.Reset();
if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
{
OnIblLoadComplete();
}
- mIblSpecularLoadTask.Reset();
}
void SceneView::OnIblLoadComplete()
void SceneView::NotifyImageBasedLightTextureChange()
{
- for(auto&& item : mItems)
+ for(auto&& item : mLightObservers)
{
if(item)
{
}
}
-bool SceneView::AddLightInternal(Scene3D::Light light)
+void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
{
- uint32_t maxNumberOfLight = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- if(mActivatedLightCount == 0)
+ if(!mShadowLight || !mSceneHolder)
{
- mActivatedLights.resize(maxNumberOfLight);
+ return;
}
- bool enabled = false;
- if(mActivatedLightCount < maxNumberOfLight)
+ if(!mShadowMapRenderTask)
{
- uint32_t newLightIndex = 0u;
- for(; newLightIndex < maxNumberOfLight; ++newLightIndex)
- {
- if(!mActivatedLights[newLightIndex])
- {
- mActivatedLights[newLightIndex] = light;
- break;
- }
- }
-
- for(auto&& item : mItems)
- {
- if(item)
- {
- item->NotifyLightAdded(newLightIndex, light);
- }
- }
-
- mActivatedLightCount++;
- enabled = true;
+ 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);
}
- return enabled;
-}
-int32_t SceneView::RemoveLightInternal(Scene3D::Light light)
-{
- int32_t removedIndex = INVALID_INDEX;
- uint32_t maxNumberOfLight = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- for(uint32_t i = 0; i < maxNumberOfLight; ++i)
+ Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer();
+ if(!currentShadowFrameBuffer ||
+ !mShadowTexture ||
+ !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize))
{
- if(mActivatedLights[i] == light)
+ 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)
{
- for(auto&& item : mItems)
+ if(item)
{
- if(item)
- {
- item->NotifyLightRemoved(i);
- }
+ item->NotifyShadowMapTexture(mShadowTexture);
}
- mActivatedLights[i].Reset();
- mActivatedLightCount--;
- removedIndex = i;
- break;
}
}
-
- return removedIndex;
}
} // namespace Internal