3D UI cleanup and update
Turns out 3D UI implementation was not flexible enough. This change allows ultimate freedom by splitting up responsibilities correctly. UIComponent is no longer responsible for storing batches and vertex data. This information was moved to new `RenderToTextureData` struct inside `UI` subsystem. `UI` and `UIComponent` are no longer friends of each other. New class `UIElement3D` was created. It is used as root UI element of UI rendered in a 3D scene. It implements `ScreenToElement()` method which is used for translating screen coordinates to element coordinates. Previously `UIComponent` did translation of these coordinates. `UIElement3D::ElementToScreen()` is not implemented at this time and returns `{-1, -1}` (invalid coordinates). It is also possible to set a custom viewport to root element of `UIComponent` and this viewport will be used for processing user input. In order to render UIElement to a texture it is enough to call SetRenderTexture(texture), where texture is set up as `TEXTURE_RENDERTARGET`. In order to properly support input of `UIElement` rendered to a texture user should subclass `UIElement` and implement `ScreenToElement()` method which properly translates global screen coordinates to local element coordinates. New API: * UIElement::SetRenderTexture(Texture2D*) * UI::SetRenderTexture(UIElement*, Texture2D*)
This commit is contained in:
parent
3b68cc6b64
commit
c5c560e759
@ -441,32 +441,34 @@ void UI::RenderUpdate()
|
||||
}
|
||||
|
||||
// Get batches for UI elements rendered into textures. Each element rendered into texture is treated as root element.
|
||||
for (Vector<WeakPtr<UIComponent> >::Iterator it = renderToTexture_.Begin(); it != renderToTexture_.End();)
|
||||
for (auto it = renderToTexture_.Begin(); it != renderToTexture_.End();)
|
||||
{
|
||||
WeakPtr<UIComponent> component = *it;
|
||||
if (component.Null() || !component->IsEnabled())
|
||||
RenderToTextureData& data = it->second_;
|
||||
if (data.rootElement_.Expired())
|
||||
it = renderToTexture_.Erase(it);
|
||||
else if (component->IsEnabled())
|
||||
else if (data.rootElement_->IsEnabled())
|
||||
{
|
||||
component->batches_.Clear();
|
||||
component->vertexData_.Clear();
|
||||
UIElement* element = component->GetRoot();
|
||||
data.batches_.Clear();
|
||||
data.vertexData_.Clear();
|
||||
UIElement* element = data.rootElement_;
|
||||
const IntVector2& size = element->GetSize();
|
||||
const IntVector2& pos = element->GetPosition();
|
||||
// Note: the scissors operate on unscaled coordinates. Scissor scaling is only performed during render
|
||||
IntRect scissor = IntRect(pos.x_, pos.y_, pos.x_ + size.x_, pos.y_ + size.y_);
|
||||
GetBatches(component->batches_, component->vertexData_, element, scissor);
|
||||
GetBatches(data.batches_, data.vertexData_, element, scissor);
|
||||
|
||||
// UIElement does not have anything to show. Insert dummy batch that will clear the texture.
|
||||
if (component->batches_.Empty())
|
||||
if (data.batches_.Empty())
|
||||
{
|
||||
UIBatch batch(element, BLEND_REPLACE, scissor, nullptr, &component->vertexData_);
|
||||
UIBatch batch(element, BLEND_REPLACE, scissor, nullptr, &data.vertexData_);
|
||||
batch.SetColor(Color::BLACK);
|
||||
batch.AddQuad(scissor.left_, scissor.top_, scissor.right_, scissor.bottom_, 0, 0);
|
||||
component->batches_.Push(batch);
|
||||
data.batches_.Push(batch);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,23 +503,23 @@ void UI::Render(bool renderUICommand)
|
||||
// Render to UIComponent textures. This is skipped when called from the RENDERUI command
|
||||
if (!renderUICommand)
|
||||
{
|
||||
for (Vector<WeakPtr<UIComponent> >::ConstIterator it = renderToTexture_.Begin(); it != renderToTexture_.End(); it++)
|
||||
for (auto it = renderToTexture_.Begin(); it != renderToTexture_.End(); it++)
|
||||
{
|
||||
WeakPtr<UIComponent> component = *it;
|
||||
if (component->IsEnabled())
|
||||
RenderToTextureData& data = it->second_;
|
||||
if (data.rootElement_->IsEnabled())
|
||||
{
|
||||
SetVertexData(component->vertexBuffer_, component->vertexData_);
|
||||
SetVertexData(component->debugVertexBuffer_, component->debugVertexData_);
|
||||
SetVertexData(data.vertexBuffer_, data.vertexData_);
|
||||
SetVertexData(data.debugVertexBuffer_, data.debugVertexData_);
|
||||
|
||||
RenderSurface* surface = component->GetTexture()->GetRenderSurface();
|
||||
RenderSurface* surface = data.texture_->GetRenderSurface();
|
||||
graphics_->SetRenderTarget(0, surface);
|
||||
graphics_->SetViewport(IntRect(0, 0, surface->GetWidth(), surface->GetHeight()));
|
||||
graphics_->Clear(Urho3D::CLEAR_COLOR);
|
||||
|
||||
Render(component->vertexBuffer_, component->batches_, 0, component->batches_.Size());
|
||||
Render(component->debugVertexBuffer_, component->debugDrawBatches_, 0, component->debugDrawBatches_.Size());
|
||||
component->debugDrawBatches_.Clear();
|
||||
component->debugVertexData_.Clear();
|
||||
Render(data.vertexBuffer_, data.batches_, 0, data.batches_.Size());
|
||||
Render(data.debugVertexBuffer_, data.debugDrawBatches_, 0, data.debugDrawBatches_.Size());
|
||||
data.debugDrawBatches_.Clear();
|
||||
data.debugVertexData_.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -546,12 +548,12 @@ void UI::DebugDraw(UIElement* element)
|
||||
element->GetDebugDrawBatches(debugDrawBatches_, debugVertexData_, scissor);
|
||||
else
|
||||
{
|
||||
for (Vector<WeakPtr<UIComponent> >::Iterator it = renderToTexture_.Begin(); it != renderToTexture_.End(); it++)
|
||||
for (auto it = renderToTexture_.Begin(); it != renderToTexture_.End(); it++)
|
||||
{
|
||||
WeakPtr<UIComponent> component = *it;
|
||||
if (component.NotNull() && component->GetRoot() == root && component->IsEnabled())
|
||||
RenderToTextureData& data = it->second_;
|
||||
if (!data.rootElement_.Expired() && data.rootElement_ == root && data.rootElement_->IsEnabled())
|
||||
{
|
||||
element->GetDebugDrawBatches(component->debugDrawBatches_, component->debugVertexData_, scissor);
|
||||
element->GetDebugDrawBatches(data.debugDrawBatches_, data.debugVertexData_, scissor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -768,16 +770,16 @@ UIElement* UI::GetElementAt(const IntVector2& position, bool enabledOnly, IntVec
|
||||
// Mouse was not hovering UI element. Check elements rendered on 3D objects.
|
||||
if (!result && renderToTexture_.Size())
|
||||
{
|
||||
for (Vector<WeakPtr<UIComponent> >::Iterator it = renderToTexture_.Begin(); it != renderToTexture_.End(); it++)
|
||||
for (auto it = renderToTexture_.Begin(); it != renderToTexture_.End(); it++)
|
||||
{
|
||||
WeakPtr<UIComponent> component = *it;
|
||||
if (component.Null() || !component->IsEnabled())
|
||||
RenderToTextureData& data = it->second_;
|
||||
if (data.rootElement_.Expired() || !data.rootElement_->IsEnabled())
|
||||
continue;
|
||||
|
||||
IntVector2 screenPosition;
|
||||
if (component->ScreenToUIPosition(position, screenPosition))
|
||||
IntVector2 screenPosition = data.rootElement_->ScreenToElement(position);
|
||||
if (data.rootElement_->GetCombinedScreenRect().IsInside(screenPosition) == INSIDE)
|
||||
{
|
||||
result = GetElementAt(component->GetRoot(), screenPosition, enabledOnly);
|
||||
result = GetElementAt(data.rootElement_, screenPosition, enabledOnly);
|
||||
if (result)
|
||||
{
|
||||
if (elementScreenPosition)
|
||||
@ -2076,16 +2078,31 @@ IntVector2 UI::GetEffectiveRootElementSize(bool applyScale) const
|
||||
return size;
|
||||
}
|
||||
|
||||
void UI::SetRenderToTexture(UIComponent* component, bool enable)
|
||||
void UI::SetRenderTexture(UIElement* element, Texture2D* texture)
|
||||
{
|
||||
WeakPtr<UIComponent> weak(component);
|
||||
if (enable)
|
||||
if (element == nullptr)
|
||||
{
|
||||
if (!renderToTexture_.Contains(weak))
|
||||
renderToTexture_.Push(weak);
|
||||
URHO3D_LOGERROR("UI::SetRenderTexture called with null element.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = renderToTexture_.Find(element);
|
||||
if (texture && it == renderToTexture_.End())
|
||||
{
|
||||
RenderToTextureData data;
|
||||
data.texture_ = texture;
|
||||
data.rootElement_ = element;
|
||||
data.vertexBuffer_ = new VertexBuffer(context_);
|
||||
data.debugVertexBuffer_ = new VertexBuffer(context_);
|
||||
renderToTexture_[element] = data;
|
||||
}
|
||||
else if (it != renderToTexture_.End())
|
||||
{
|
||||
if (texture == nullptr)
|
||||
renderToTexture_.Erase(it);
|
||||
else
|
||||
it->second_.texture_ = texture;
|
||||
}
|
||||
else
|
||||
renderToTexture_.Remove(weak);
|
||||
}
|
||||
|
||||
void RegisterUILibrary(Context* context)
|
||||
@ -2114,6 +2131,7 @@ void RegisterUILibrary(Context* context)
|
||||
ProgressBar::RegisterObject(context);
|
||||
ToolTip::RegisterObject(context);
|
||||
UIComponent::RegisterObject(context);
|
||||
UIElement3D::RegisterObject(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Core/Object.h"
|
||||
#include "../Graphics/VertexBuffer.h"
|
||||
#include "../UI/Cursor.h"
|
||||
#include "../UI/UIBatch.h"
|
||||
|
||||
@ -48,7 +49,6 @@ class ResourceCache;
|
||||
class Timer;
|
||||
class UIBatch;
|
||||
class UIElement;
|
||||
class VertexBuffer;
|
||||
class XMLElement;
|
||||
class XMLFile;
|
||||
class RenderSurface;
|
||||
@ -212,8 +212,8 @@ public:
|
||||
/// Return root element custom size. Returns 0,0 when custom size is not being used and automatic resizing according to window size is in use instead (default.)
|
||||
const IntVector2& GetCustomSize() const { return customSize_; }
|
||||
|
||||
/// Register UIElement for being rendered into a texture.
|
||||
void SetRenderToTexture(UIComponent* component, bool enable);
|
||||
/// Set texture to which element will be rendered.
|
||||
void SetRenderTexture(UIElement* element, Texture2D* texture);
|
||||
|
||||
/// Data structure used to represent the drag data associated to a UIElement.
|
||||
struct DragData
|
||||
@ -233,6 +233,27 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
/// Data structured used to hold data of UI elements that are rendered to texture.
|
||||
struct RenderToTextureData
|
||||
{
|
||||
/// UIElement to be rendered into texture.
|
||||
WeakPtr<UIElement> rootElement_;
|
||||
/// Texture that UIElement will be rendered into.
|
||||
SharedPtr<Texture2D> texture_;
|
||||
/// UI rendering batches.
|
||||
PODVector<UIBatch> batches_;
|
||||
/// UI rendering vertex data.
|
||||
PODVector<float> vertexData_;
|
||||
/// UI vertex buffer.
|
||||
SharedPtr<VertexBuffer> vertexBuffer_;
|
||||
/// UI rendering batches for debug draw.
|
||||
PODVector<UIBatch> debugDrawBatches_;
|
||||
/// UI rendering vertex data for debug draw.
|
||||
PODVector<float> debugVertexData_;
|
||||
/// UI debug geometry vertex buffer.
|
||||
SharedPtr<VertexBuffer> debugVertexBuffer_;
|
||||
};
|
||||
|
||||
/// Initialize when screen mode initially set.
|
||||
void Initialize();
|
||||
/// Update UI element logic recursively.
|
||||
@ -398,9 +419,7 @@ private:
|
||||
/// Root element custom size. 0,0 for automatic resizing (default.)
|
||||
IntVector2 customSize_;
|
||||
/// Elements that should be rendered to textures.
|
||||
Vector<WeakPtr<UIComponent> > renderToTexture_;
|
||||
|
||||
friend class UIComponent;
|
||||
HashMap<UIElement*, RenderToTextureData> renderToTexture_;
|
||||
};
|
||||
|
||||
/// Register UI library objects.
|
||||
|
@ -45,16 +45,21 @@ static int const UICOMPONENT_DEFAULT_TEXTURE_SIZE = 512;
|
||||
static int const UICOMPONENT_MIN_TEXTURE_SIZE = 64;
|
||||
static int const UICOMPONENT_MAX_TEXTURE_SIZE = 4096;
|
||||
|
||||
|
||||
UIComponent::UIComponent(Context* context) :
|
||||
Component(context),
|
||||
isStaticModelOwned_(false)
|
||||
{
|
||||
vertexBuffer_ = new VertexBuffer(context_);
|
||||
debugVertexBuffer_ = new VertexBuffer(context_);
|
||||
texture_ = context_->CreateObject<Texture2D>();
|
||||
texture_->SetFilterMode(FILTER_BILINEAR);
|
||||
texture_->SetAddressMode(COORD_U, ADDRESS_CLAMP);
|
||||
texture_->SetAddressMode(COORD_V, ADDRESS_CLAMP);
|
||||
texture_->SetNumLevels(1); // No mipmaps
|
||||
|
||||
rootElement_ = context_->CreateObject<UIElement>();
|
||||
rootElement_ = context_->CreateObject<UIElement3D>();
|
||||
rootElement_->SetUIComponent(this);
|
||||
rootElement_->SetTraversalMode(TM_BREADTH_FIRST);
|
||||
rootElement_->SetEnabled(true);
|
||||
|
||||
material_ = context_->CreateObject<Material>();
|
||||
material_->SetTechnique(0, GetSubsystem<ResourceCache>()->GetResource<Technique>("Techniques/Diff.xml"));
|
||||
@ -63,6 +68,7 @@ UIComponent::UIComponent(Context* context) :
|
||||
SubscribeToEvent(rootElement_, E_RESIZED, URHO3D_HANDLER(UIComponent, OnElementResized));
|
||||
|
||||
// Triggers resizing of texture.
|
||||
rootElement_->SetRenderTexture(texture_);
|
||||
rootElement_->SetSize(UICOMPONENT_DEFAULT_TEXTURE_SIZE, UICOMPONENT_DEFAULT_TEXTURE_SIZE);
|
||||
}
|
||||
|
||||
@ -90,6 +96,10 @@ Texture2D* UIComponent::GetTexture() const
|
||||
return texture_;
|
||||
}
|
||||
|
||||
StaticModel* UIComponent::GetModel() const
|
||||
{
|
||||
return model_;
|
||||
}
|
||||
|
||||
void UIComponent::OnNodeSet(Node* node)
|
||||
{
|
||||
@ -102,9 +112,11 @@ void UIComponent::OnNodeSet(Node* node)
|
||||
model_ = node->CreateComponent<StaticModel>();
|
||||
}
|
||||
model_->SetMaterial(material_);
|
||||
rootElement_->SetRenderTexture(texture_);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootElement_->SetRenderTexture(nullptr);
|
||||
model_->SetMaterial(nullptr);
|
||||
if (isStaticModelOwned_)
|
||||
{
|
||||
@ -113,11 +125,6 @@ void UIComponent::OnNodeSet(Node* node)
|
||||
}
|
||||
model_ = nullptr;
|
||||
}
|
||||
|
||||
UI* ui = GetSubsystem<UI>();
|
||||
// May be null on shutdown
|
||||
if (ui)
|
||||
ui->SetRenderToTexture(this, node != nullptr);
|
||||
}
|
||||
|
||||
void UIComponent::OnElementResized(StringHash eventType, VariantMap& args)
|
||||
@ -134,38 +141,42 @@ void UIComponent::OnElementResized(StringHash eventType, VariantMap& args)
|
||||
}
|
||||
|
||||
if (texture_->SetSize(width, height, GetSubsystem<Graphics>()->GetRGBAFormat(), TEXTURE_RENDERTARGET))
|
||||
{
|
||||
texture_->SetFilterMode(FILTER_BILINEAR);
|
||||
texture_->SetAddressMode(COORD_U, ADDRESS_CLAMP);
|
||||
texture_->SetAddressMode(COORD_V, ADDRESS_CLAMP);
|
||||
texture_->SetNumLevels(1); // No mipmaps
|
||||
texture_->GetRenderSurface()->SetUpdateMode(SURFACE_MANUALUPDATE);
|
||||
}
|
||||
else
|
||||
URHO3D_LOGERROR("UIComponent: resizing texture failed.");
|
||||
}
|
||||
|
||||
bool UIComponent::ScreenToUIPosition(IntVector2 screenPos, IntVector2& result)
|
||||
IntVector2 UIElement3D::ScreenToElement(const IntVector2& screenPos)
|
||||
{
|
||||
Scene* scene = GetScene();
|
||||
IntVector2 result(-1, -1);
|
||||
|
||||
Scene* scene = component_->GetScene();
|
||||
if (!scene)
|
||||
return false;
|
||||
return result;
|
||||
|
||||
Renderer* renderer = GetSubsystem<Renderer>();
|
||||
if (!renderer)
|
||||
return false;
|
||||
return result;
|
||||
|
||||
// \todo Always uses the first viewport, in case there are multiple
|
||||
Viewport* viewport = renderer->GetViewportForScene(scene, 0);
|
||||
Octree* octree = scene->GetComponent<Octree>();
|
||||
Viewport* viewport = viewport_;
|
||||
if (viewport == nullptr)
|
||||
viewport = renderer->GetViewportForScene(scene, 0);
|
||||
|
||||
if (!viewport || !octree)
|
||||
return false;
|
||||
return result;
|
||||
|
||||
if (viewport->GetScene() != scene)
|
||||
{
|
||||
URHO3D_LOGERROR("UIComponent and Viewport set to component's root element belong to different scenes.");
|
||||
return result;
|
||||
}
|
||||
|
||||
Camera* camera = viewport->GetCamera();
|
||||
|
||||
if (!camera)
|
||||
return false;
|
||||
return result;
|
||||
|
||||
IntRect rect = viewport->GetRect();
|
||||
if (rect == IntRect::ZERO)
|
||||
@ -182,25 +193,51 @@ bool UIComponent::ScreenToUIPosition(IntVector2 screenPos, IntVector2& result)
|
||||
octree->Raycast(query);
|
||||
|
||||
if (queryResultVector.Empty())
|
||||
return false;
|
||||
return result;
|
||||
|
||||
for (unsigned i = 0; i < queryResultVector.Size(); i++)
|
||||
{
|
||||
RayQueryResult& queryResult = queryResultVector[i];
|
||||
if (queryResult.drawable_ != model_)
|
||||
if (queryResult.drawable_ != component_->GetModel())
|
||||
{
|
||||
// ignore billboard sets by default
|
||||
if (queryResult.drawable_->GetTypeInfo()->IsTypeOf(BillboardSet::GetTypeStatic()))
|
||||
continue;
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector2& uv = queryResult.textureUV_;
|
||||
result = IntVector2(static_cast<int>(uv.x_ * rootElement_->GetWidth()),
|
||||
static_cast<int>(uv.y_ * rootElement_->GetHeight()));
|
||||
return true;
|
||||
result = IntVector2(static_cast<int>(uv.x_ * component_->GetRoot()->GetWidth()),
|
||||
static_cast<int>(uv.y_ * component_->GetRoot()->GetHeight()));
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
IntVector2 UIElement3D::ElementToScreen(const IntVector2& position)
|
||||
{
|
||||
URHO3D_LOGERROR("UIElement3D::ElementToScreen is not implemented.");
|
||||
return {-1, -1};
|
||||
}
|
||||
|
||||
void UIElement3D::RegisterObject(Context* context)
|
||||
{
|
||||
context->RegisterFactory<UIElement3D>();
|
||||
}
|
||||
|
||||
UIElement3D::UIElement3D(Context* context)
|
||||
: UIElement(context)
|
||||
{
|
||||
}
|
||||
|
||||
void UIElement3D::SetUIComponent(UIComponent* component)
|
||||
{
|
||||
component_ = component;
|
||||
}
|
||||
|
||||
void UIElement3D::SetViewport(Viewport* viewport)
|
||||
{
|
||||
viewport_ = viewport;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Scene/Component.h"
|
||||
#include "../UI/UIElement.h"
|
||||
|
||||
namespace Urho3D
|
||||
{
|
||||
@ -33,6 +34,7 @@ class Viewport;
|
||||
class UIElement;
|
||||
class UIBatch;
|
||||
class VertexBuffer;
|
||||
class UIElement3D;
|
||||
|
||||
class URHO3D_API UIComponent : public Component
|
||||
{
|
||||
@ -52,6 +54,8 @@ public:
|
||||
Material* GetMaterial() const;
|
||||
/// Return texture which will be used for rendering UI to.
|
||||
Texture2D* GetTexture() const;
|
||||
/// Return static model on to which UI will be rendered.
|
||||
StaticModel* GetModel() const;
|
||||
|
||||
protected:
|
||||
/// Material that is set to the model.
|
||||
@ -61,29 +65,41 @@ protected:
|
||||
/// Model that texture will be applied to.
|
||||
SharedPtr<StaticModel> model_;
|
||||
/// UIElement to be rendered into texture.
|
||||
SharedPtr<UIElement> rootElement_;
|
||||
/// UI rendering batches.
|
||||
PODVector<UIBatch> batches_;
|
||||
/// UI rendering vertex data.
|
||||
PODVector<float> vertexData_;
|
||||
/// UI vertex buffer.
|
||||
SharedPtr<VertexBuffer> vertexBuffer_;
|
||||
/// UI rendering batches for debug draw.
|
||||
PODVector<UIBatch> debugDrawBatches_;
|
||||
/// UI rendering vertex data for debug draw.
|
||||
PODVector<float> debugVertexData_;
|
||||
/// UI debug geometry vertex buffer.
|
||||
SharedPtr<VertexBuffer> debugVertexBuffer_;
|
||||
SharedPtr<UIElement3D> rootElement_;
|
||||
/// Is StaticModel component created by this component.
|
||||
bool isStaticModelOwned_;
|
||||
|
||||
/// Handle component being added to Node or removed from it.
|
||||
virtual void OnNodeSet(Node* node) override;
|
||||
/// Handle resizing of element. Setting size of element will automatically resize texture. UIElement size matches size of texture.
|
||||
void OnElementResized(StringHash eventType, VariantMap& args);
|
||||
/// Convert screen position to position on UIElement.
|
||||
bool ScreenToUIPosition(IntVector2 screenPos, IntVector2& result);
|
||||
};
|
||||
|
||||
friend class UI;
|
||||
class URHO3D_API UIElement3D : public UIElement
|
||||
{
|
||||
URHO3D_OBJECT(UIElement3D, UIElement);
|
||||
public:
|
||||
/// Construct.
|
||||
UIElement3D(Context* context);
|
||||
/// Destruct.
|
||||
virtual ~UIElement3D() override = default;
|
||||
/// Register object factory.
|
||||
static void RegisterObject(Context* context);
|
||||
|
||||
/// Set UIComponent which is using this element as root element.
|
||||
void SetUIComponent(UIComponent* component);
|
||||
/// Set active viewport through which this element is rendered. If viewport is not set, it defaults to first viewport.
|
||||
void SetViewport(Viewport* viewport);
|
||||
/// Convert screen coordinates to element coordinates.
|
||||
IntVector2 ScreenToElement(const IntVector2& screenPos) override;
|
||||
/// Convert element coordinates to screen coordinates.
|
||||
IntVector2 ElementToScreen(const IntVector2& position) override;
|
||||
|
||||
protected:
|
||||
/// A UIComponent which owns this element.
|
||||
WeakPtr<UIComponent> component_;
|
||||
/// Viewport which renders this element.
|
||||
WeakPtr<Viewport> viewport_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -2277,4 +2277,10 @@ void UIElement::HandlePostUpdate(StringHash eventType, VariantMap& eventData)
|
||||
UpdateAttributeAnimations(eventData[P_TIMESTEP].GetFloat());
|
||||
}
|
||||
|
||||
void UIElement::SetRenderTexture(Texture2D* texture)
|
||||
{
|
||||
if (UI* ui = GetSubsystem<UI>())
|
||||
ui->SetRenderTexture(this, texture);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ static const unsigned DD_SOURCE_AND_TARGET = 0x3;
|
||||
|
||||
class Cursor;
|
||||
class ResourceCache;
|
||||
class Texture2D;
|
||||
|
||||
/// Base class for %UI elements.
|
||||
class URHO3D_API UIElement : public Animatable
|
||||
@ -640,6 +641,9 @@ public:
|
||||
/// Return effective minimum size, also considering layout. Used internally.
|
||||
IntVector2 GetEffectiveMinSize() const;
|
||||
|
||||
/// Set texture to which element will be rendered.
|
||||
void SetRenderTexture(Texture2D* texture);
|
||||
|
||||
protected:
|
||||
/// Handle attribute animation added.
|
||||
virtual void OnAttributeAnimationAdded() override;
|
||||
|
Loading…
Reference in New Issue
Block a user