mirror of
https://github.com/overte-org/overte.git
synced 2025-06-06 03:11:07 +02:00
Moved draw frustum job to render DrawTask and made generic. A couple of fixes as requested by @samcake
This commit is contained in:
parent
bf46ccefaf
commit
f47a3e7d2c
7 changed files with 165 additions and 118 deletions
|
@ -44,8 +44,6 @@
|
||||||
#include "DrawHaze.h"
|
#include "DrawHaze.h"
|
||||||
#include "HighlightEffect.h"
|
#include "HighlightEffect.h"
|
||||||
|
|
||||||
#include <gpu/StandardShaderLib.h>
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
@ -193,14 +191,18 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
||||||
|
|
||||||
task.addJob<EndGPURangeTimer>("HighlightRangeTimer", outlineRangeTimer);
|
task.addJob<EndGPURangeTimer>("HighlightRangeTimer", outlineRangeTimer);
|
||||||
|
|
||||||
{ // DEbug the bounds of the rendered items, still look at the zbuffer
|
{ // Debug the bounds of the rendered items, still look at the zbuffer
|
||||||
task.addJob<DrawBounds>("DrawMetaBounds", metas);
|
task.addJob<DrawBounds>("DrawMetaBounds", metas);
|
||||||
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
task.addJob<DrawBounds>("DrawOpaqueBounds", opaques);
|
||||||
task.addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
task.addJob<DrawBounds>("DrawTransparentBounds", transparents);
|
||||||
|
|
||||||
task.addJob<DrawBounds>("DrawLightBounds", lights);
|
task.addJob<DrawBounds>("DrawLightBounds", lights);
|
||||||
task.addJob<DrawBounds>("DrawZones", zones);
|
task.addJob<DrawBounds>("DrawZones", zones);
|
||||||
task.addJob<DrawFrustums>("DrawFrustums");
|
const auto frustums = task.addJob<ExtractFrustums>("ExtractFrustums");
|
||||||
|
const auto viewFrustum = frustums.getN<ExtractFrustums::Output>(ExtractFrustums::VIEW_FRUSTUM);
|
||||||
|
const auto shadowFrustum = frustums.getN<ExtractFrustums::Output>(ExtractFrustums::SHADOW_FRUSTUM);
|
||||||
|
task.addJob<DrawFrustum>("DrawViewFrustum", viewFrustum, glm::vec3(1.0f, 1.0f, 0.0f));
|
||||||
|
task.addJob<DrawFrustum>("DrawShadowFrustum", shadowFrustum, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||||
|
|
||||||
// Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true
|
// Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true
|
||||||
task.addJob<DrawBounds>("DrawSelectionBounds", selectedItems);
|
task.addJob<DrawBounds>("DrawSelectionBounds", selectedItems);
|
||||||
|
@ -533,88 +535,32 @@ void Blit::run(const RenderContextPointer& renderContext, const gpu::Framebuffer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawFrustums::configure(const Config& configuration) {
|
void ExtractFrustums::run(const render::RenderContextPointer& renderContext, Output& output) {
|
||||||
_updateFrustums = !configuration.isFrozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawFrustums::run(const render::RenderContextPointer& renderContext) {
|
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->_context);
|
assert(renderContext->args->_context);
|
||||||
|
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
static uint8_t indexData[] = { 0, 1, 2, 3, 0, 4, 5, 6, 7, 4, 5, 1, 2, 6, 7, 3 };
|
|
||||||
|
|
||||||
if (!_frustumMeshIndices._buffer) {
|
// Return view frustum
|
||||||
auto indices = std::make_shared<gpu::Buffer>(sizeof(indexData), indexData);
|
auto& viewFrustum = output[VIEW_FRUSTUM].edit<ViewFrustumPointer>();
|
||||||
_frustumMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX));
|
if (!viewFrustum) {
|
||||||
_viewFrustumMeshVertices = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ);
|
viewFrustum = std::make_shared<ViewFrustum>(args->getViewFrustum());
|
||||||
_viewFrustumMeshStream.addBuffer(_viewFrustumMeshVertices._buffer, _viewFrustumMeshVertices._offset, _viewFrustumMeshVertices._stride);
|
} else {
|
||||||
_shadowFrustumMeshVertices = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ);
|
*viewFrustum = args->getViewFrustum();
|
||||||
_shadowFrustumMeshStream.addBuffer(_shadowFrustumMeshVertices._buffer, _shadowFrustumMeshVertices._offset, _shadowFrustumMeshVertices._stride);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_updateFrustums) {
|
// Return shadow frustum
|
||||||
updateFrustum(args->getViewFrustum(), _viewFrustumMeshVertices);
|
auto& shadowFrustum = output[SHADOW_FRUSTUM].edit<ViewFrustumPointer>();
|
||||||
|
auto lightStage = args->_scene->getStage<LightStage>(LightStage::getName());
|
||||||
|
if (lightStage) {
|
||||||
|
auto globalShadow = lightStage->getCurrentKeyShadow();
|
||||||
|
|
||||||
auto lightStage = renderContext->_scene->getStage<LightStage>();
|
|
||||||
assert(lightStage);
|
|
||||||
|
|
||||||
const auto globalShadow = lightStage->getCurrentKeyShadow();
|
|
||||||
if (globalShadow) {
|
if (globalShadow) {
|
||||||
updateFrustum(*globalShadow->getFrustum(), _shadowFrustumMeshVertices);
|
shadowFrustum = globalShadow->getFrustum();
|
||||||
|
} else {
|
||||||
|
shadowFrustum.reset();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
shadowFrustum.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_pipeline) {
|
|
||||||
auto vs = gpu::StandardShaderLib::getDrawTransformVertexPositionVS();
|
|
||||||
auto ps = gpu::StandardShaderLib::getDrawColorPS();
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding("color", 0));
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
|
|
||||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
|
||||||
state->setDepthTest(gpu::State::DepthTest(true, false));
|
|
||||||
_pipeline = gpu::Pipeline::create(program, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the frustums in wireframe
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
|
||||||
args->_batch = &batch;
|
|
||||||
batch.setViewportTransform(args->_viewport);
|
|
||||||
batch.setStateScissorRect(args->_viewport);
|
|
||||||
|
|
||||||
glm::mat4 projMat;
|
|
||||||
Transform viewMat;
|
|
||||||
args->getViewFrustum().evalProjectionMatrix(projMat);
|
|
||||||
args->getViewFrustum().evalViewTransform(viewMat);
|
|
||||||
|
|
||||||
batch.setProjectionTransform(projMat);
|
|
||||||
batch.setViewTransform(viewMat);
|
|
||||||
batch.setPipeline(_pipeline);
|
|
||||||
batch.setIndexBuffer(_frustumMeshIndices);
|
|
||||||
|
|
||||||
batch._glUniform4f(0, 1.0f, 1.0f, 0.0f, 1.0f);
|
|
||||||
batch.setInputStream(0, _viewFrustumMeshStream);
|
|
||||||
batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U);
|
|
||||||
|
|
||||||
batch._glUniform4f(0, 1.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
batch.setInputStream(0, _shadowFrustumMeshStream);
|
|
||||||
batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U);
|
|
||||||
|
|
||||||
args->_batch = nullptr;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawFrustums::updateFrustum(const ViewFrustum& frustum, gpu::BufferView& vertexBuffer) {
|
|
||||||
auto& vertices = vertexBuffer.edit<std::array<glm::vec3, 8U> >();
|
|
||||||
vertices[0] = frustum.getNearTopLeft();
|
|
||||||
vertices[1] = frustum.getNearTopRight();
|
|
||||||
vertices[2] = frustum.getNearBottomRight();
|
|
||||||
vertices[3] = frustum.getNearBottomLeft();
|
|
||||||
vertices[4] = frustum.getFarTopLeft();
|
|
||||||
vertices[5] = frustum.getFarTopRight();
|
|
||||||
vertices[6] = frustum.getFarBottomRight();
|
|
||||||
vertices[7] = frustum.getFarBottomLeft();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,38 +170,20 @@ public:
|
||||||
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
|
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawFrustumsConfig : public render::Job::Config {
|
class ExtractFrustums {
|
||||||
Q_OBJECT
|
|
||||||
Q_PROPERTY(bool isFrozen MEMBER isFrozen NOTIFY dirty)
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DrawFrustumsConfig(bool enabled = false) : JobConfig(enabled) {}
|
enum Frustum {
|
||||||
|
VIEW_FRUSTUM,
|
||||||
|
SHADOW_FRUSTUM,
|
||||||
|
|
||||||
bool isFrozen{ false };
|
FRUSTUM_COUNT
|
||||||
signals:
|
};
|
||||||
void dirty();
|
|
||||||
|
|
||||||
};
|
using Output = render::VaryingArray<ViewFrustumPointer, FRUSTUM_COUNT>;
|
||||||
|
using JobModel = render::Job::ModelO<ExtractFrustums, Output>;
|
||||||
|
|
||||||
class DrawFrustums {
|
void run(const render::RenderContextPointer& renderContext, Output& output);
|
||||||
public:
|
|
||||||
using Config = DrawFrustumsConfig;
|
|
||||||
using JobModel = render::Job::Model<DrawFrustums, Config>;
|
|
||||||
|
|
||||||
void configure(const Config& configuration);
|
|
||||||
void run(const render::RenderContextPointer& renderContext);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
bool _updateFrustums{ true };
|
|
||||||
gpu::PipelinePointer _pipeline;
|
|
||||||
gpu::BufferView _frustumMeshIndices;
|
|
||||||
gpu::BufferView _viewFrustumMeshVertices;
|
|
||||||
gpu::BufferView _shadowFrustumMeshVertices;
|
|
||||||
gpu::BufferStream _viewFrustumMeshStream;
|
|
||||||
gpu::BufferStream _shadowFrustumMeshStream;
|
|
||||||
|
|
||||||
static void updateFrustum(const ViewFrustum& frustum, gpu::BufferView& vertexBuffer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderDeferredTaskConfig : public render::Task::Config {
|
class RenderDeferredTaskConfig : public render::Task::Config {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
#include <gpu/StandardShaderLib.h>
|
||||||
|
|
||||||
#include <drawItemBounds_vert.h>
|
#include <drawItemBounds_vert.h>
|
||||||
#include <drawItemBounds_frag.h>
|
#include <drawItemBounds_frag.h>
|
||||||
|
@ -215,3 +215,85 @@ void DrawBounds::run(const RenderContextPointer& renderContext,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::PipelinePointer DrawFrustum::_pipeline;
|
||||||
|
gpu::BufferView DrawFrustum::_frustumMeshIndices;
|
||||||
|
|
||||||
|
DrawFrustum::DrawFrustum(const glm::vec3& color) :
|
||||||
|
_color{ color } {
|
||||||
|
_frustumMeshVertices = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ);
|
||||||
|
_frustumMeshStream.addBuffer(_frustumMeshVertices._buffer, _frustumMeshVertices._offset, _frustumMeshVertices._stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawFrustum::configure(const Config& configuration) {
|
||||||
|
_updateFrustum = !configuration.isFrozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawFrustum::run(const render::RenderContextPointer& renderContext, const Input& input) {
|
||||||
|
assert(renderContext->args);
|
||||||
|
assert(renderContext->args->_context);
|
||||||
|
|
||||||
|
RenderArgs* args = renderContext->args;
|
||||||
|
if (input) {
|
||||||
|
const auto& frustum = *input;
|
||||||
|
|
||||||
|
static uint8_t indexData[] = { 0, 1, 2, 3, 0, 4, 5, 6, 7, 4, 5, 1, 2, 6, 7, 3 };
|
||||||
|
|
||||||
|
if (!_frustumMeshIndices._buffer) {
|
||||||
|
auto indices = std::make_shared<gpu::Buffer>(sizeof(indexData), indexData);
|
||||||
|
_frustumMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_pipeline) {
|
||||||
|
auto vs = gpu::StandardShaderLib::getDrawTransformVertexPositionVS();
|
||||||
|
auto ps = gpu::StandardShaderLib::getDrawColorPS();
|
||||||
|
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||||
|
|
||||||
|
gpu::Shader::BindingSet slotBindings;
|
||||||
|
slotBindings.insert(gpu::Shader::Binding("color", 0));
|
||||||
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
|
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||||
|
state->setDepthTest(gpu::State::DepthTest(true, false));
|
||||||
|
_pipeline = gpu::Pipeline::create(program, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_updateFrustum) {
|
||||||
|
updateFrustum(frustum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the frustums in wireframe
|
||||||
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
|
args->_batch = &batch;
|
||||||
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
batch.setStateScissorRect(args->_viewport);
|
||||||
|
|
||||||
|
glm::mat4 projMat;
|
||||||
|
Transform viewMat;
|
||||||
|
args->getViewFrustum().evalProjectionMatrix(projMat);
|
||||||
|
args->getViewFrustum().evalViewTransform(viewMat);
|
||||||
|
|
||||||
|
batch.setProjectionTransform(projMat);
|
||||||
|
batch.setViewTransform(viewMat);
|
||||||
|
batch.setPipeline(_pipeline);
|
||||||
|
batch.setIndexBuffer(_frustumMeshIndices);
|
||||||
|
|
||||||
|
batch._glUniform4f(0, _color.x, _color.y, _color.z, 1.0f);
|
||||||
|
batch.setInputStream(0, _frustumMeshStream);
|
||||||
|
batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U);
|
||||||
|
|
||||||
|
args->_batch = nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawFrustum::updateFrustum(const ViewFrustum& frustum) {
|
||||||
|
auto& vertices = _frustumMeshVertices.edit<std::array<glm::vec3, 8U> >();
|
||||||
|
vertices[0] = frustum.getNearTopLeft();
|
||||||
|
vertices[1] = frustum.getNearTopRight();
|
||||||
|
vertices[2] = frustum.getNearBottomRight();
|
||||||
|
vertices[3] = frustum.getNearBottomLeft();
|
||||||
|
vertices[4] = frustum.getFarTopLeft();
|
||||||
|
vertices[5] = frustum.getFarTopRight();
|
||||||
|
vertices[6] = frustum.getFarBottomRight();
|
||||||
|
vertices[7] = frustum.getFarBottomLeft();
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,43 @@ private:
|
||||||
int _colorLocation { -1 };
|
int _colorLocation { -1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DrawFrustumConfig : public render::JobConfig {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool isFrozen MEMBER isFrozen NOTIFY dirty)
|
||||||
|
public:
|
||||||
|
|
||||||
|
DrawFrustumConfig(bool enabled = false) : JobConfig(enabled) {}
|
||||||
|
|
||||||
|
bool isFrozen{ false };
|
||||||
|
signals:
|
||||||
|
void dirty();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class DrawFrustum {
|
||||||
|
public:
|
||||||
|
using Config = DrawFrustumConfig;
|
||||||
|
using Input = ViewFrustumPointer;
|
||||||
|
using JobModel = render::Job::ModelI<DrawFrustum, Input, Config>;
|
||||||
|
|
||||||
|
DrawFrustum(const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
void configure(const Config& configuration);
|
||||||
|
void run(const render::RenderContextPointer& renderContext, const Input& input);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static gpu::PipelinePointer _pipeline;
|
||||||
|
static gpu::BufferView _frustumMeshIndices;
|
||||||
|
|
||||||
|
bool _updateFrustum{ true };
|
||||||
|
gpu::BufferView _frustumMeshVertices;
|
||||||
|
gpu::BufferStream _frustumMeshStream;
|
||||||
|
glm::vec3 _color;
|
||||||
|
|
||||||
|
void updateFrustum(const ViewFrustum& frustum);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_render_DrawTask_h
|
#endif // hifi_render_DrawTask_h
|
||||||
|
|
|
@ -151,11 +151,7 @@ void DepthSortShapesAndComputeBounds::run(const RenderContextPointer& renderCont
|
||||||
AABox bounds;
|
AABox bounds;
|
||||||
|
|
||||||
depthSortItems(renderContext, _frontToBack, inItems, outItems->second, &bounds);
|
depthSortItems(renderContext, _frontToBack, inItems, outItems->second, &bounds);
|
||||||
if (!outBounds.isNull()) {
|
outBounds += bounds;
|
||||||
outBounds += bounds;
|
|
||||||
} else {
|
|
||||||
outBounds = bounds;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ public:
|
||||||
|
|
||||||
Vec4 transform(const Vec4& pos) const;
|
Vec4 transform(const Vec4& pos) const;
|
||||||
Vec3 transform(const Vec3& pos) const;
|
Vec3 transform(const Vec3& pos) const;
|
||||||
Vec3 transformDirection(const Vec3& pos) const;
|
Vec3 transformDirection(const Vec3& dir) const;
|
||||||
|
|
||||||
bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); }
|
bool containsNaN() const { return isNaN(_rotation) || isNaN(glm::dot(_scale, _translation)); }
|
||||||
|
|
||||||
|
@ -542,10 +542,10 @@ inline Transform::Vec3 Transform::transform(const Vec3& pos) const {
|
||||||
return Vec3(result.x / result.w, result.y / result.w, result.z / result.w);
|
return Vec3(result.x / result.w, result.y / result.w, result.z / result.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Transform::Vec3 Transform::transformDirection(const Vec3& pos) const {
|
inline Transform::Vec3 Transform::transformDirection(const Vec3& dir) const {
|
||||||
Mat4 m;
|
Mat4 m;
|
||||||
getMatrix(m);
|
getMatrix(m);
|
||||||
Vec4 result = m * Vec4(pos, 0.0f);
|
Vec4 result = m * Vec4(dir, 0.0f);
|
||||||
return Vec3(result.x, result.y, result.z);
|
return Vec3(result.x, result.y, result.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,20 +14,24 @@ import QtQuick.Controls 1.4
|
||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
spacing: 8
|
spacing: 8
|
||||||
property var config: Render.getConfig("RenderMainView.DrawFrustums");
|
property var viewConfig: Render.getConfig("RenderMainView.DrawViewFrustum");
|
||||||
|
property var shadowConfig: Render.getConfig("RenderMainView.DrawShadowFrustum");
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
config.enabled = true;
|
viewConfig.enabled = true;
|
||||||
|
shadowConfig.enabled = true;
|
||||||
}
|
}
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
config.enabled = false;
|
viewConfig.enabled = false;
|
||||||
|
shadowConfig.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
text: "Freeze Frustums"
|
text: "Freeze Frustums"
|
||||||
checked: false
|
checked: false
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
config.isFrozen = checked;
|
viewConfig.isFrozen = checked;
|
||||||
|
shadowConfig.isFrozen = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row {
|
Row {
|
||||||
|
@ -39,7 +43,7 @@ Column {
|
||||||
}
|
}
|
||||||
Label {
|
Label {
|
||||||
text: "Shadow"
|
text: "Shadow"
|
||||||
color: "red"
|
color: "blue"
|
||||||
font.italic: true
|
font.italic: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue