View Issue Details

IDProjectCategoryView StatusLast Update
0002330NoesisGUIC++ SDKpublic2024-05-23 19:38
Reporterjsantos Assigned Tosfernandez  
PrioritynormalSeverityfeature 
Status resolvedResolutionfixed 
Product Version3.1 
Target Version3.2.4Fixed in Version3.2.4 
Summary0002330: Support VisualBrush as an OpacityMask
Description

Use cases:

  • Animating a vector mask (bezier path, path, shape etc.) to png sequences, images or other vectors. When you apply a mask at the moment, it disappears from view which means we then can't animate it.
  • Masking and displacing localised text with vector shapes
  • Feathered masking and animating such masks.
PlatformAny

Activities

jsantos

jsantos

2022-04-25 17:37

manager   ~0007912

Last edited: 2022-04-25 17:39

This is also useful for 9-slice opacity masks. Right now, we are using a custom shader for this:


<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions">
<Image x:Name="img" Source="Images/map.png" Margin="100">
<Image.OpacityMask>
<ImageBrush ImageSource="Images/border-mask.png">
<ImageBrush.Shader>
<noesis:NineSliceMaskBrushShader Slices="20,30,40,54" Width="{Binding ActualWidth, ElementName=img}" Height="{Binding ActualHeight, ElementName=img}"/>
</ImageBrush.Shader>
</ImageBrush>
</Image.OpacityMask>
</Image>
</Grid>

Note that right now, using OpacityMask is always using an offscreen phase, but in this is case it shouldn't be necessary because is being applied to an image.

sfernandez

sfernandez

2022-07-26 10:08

manager   ~0008031

This issue is going to be implemented for the next major version coming in a few months.
I'm updating the target version to correctly reflect that.

jsantos

jsantos

2023-04-26 14:11

manager   ~0008462

Attaching the custom shader we were using for this.

NineSliceMask.hlsli (920 bytes)   
#define PAINT_PATTERN 1
#define CUSTOM_PATTERN 1
#include "../../../Render/D3D11RenderDevice/Src/ShaderPS.hlsl"

cbuffer Constants: register(b1)
{
    float left, top, right, bottom;
    float width, height;
}

float slice(float p, float p0, float p1, float max, float scale)
{
    if (p <= p0)
    {
        return p * scale;
    }
    else if (p >= p1)
    {
        return 1.0 - (max - p) * scale;
    }
    else
    {
        float s = (p - p0) / (p1 - p0);
        return lerp(p0 * scale, 1.0 - (max - p1) * scale, s);
    }
}

half4 GetCustomPattern(in In i)
{
    float texWidth, texHeight;
    pattern.GetDimensions(texWidth, texHeight);

    float u = slice(i.uv0.x * width, left, width - right, width, 1.0 / texWidth);
    float v = slice(i.uv0.y * height, top, height - bottom, height, 1.0 / texHeight);

    return pattern.SampleLevel(patternSampler, float2(u, v), 0);
}
NineSliceMask.hlsli (920 bytes)   
NineSliceMask_Opacity.hlsl (56 bytes)   
#define EFFECT_OPACITY 1
#include "NineSliceMask.hlsli"
NineSliceMaskBrushShader.cpp (4,044 bytes)   
//////////////////////////////////////////////////////////////////////////////////////////////////////
//// NoesisGUI - http://www.noesisengine.com
//// Copyright (c) 2013 Noesis Technologies S.L. All Rights Reserved.
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
//#include "NineSliceMaskBrushShader.h"
//
//#include <NsCore/ReflectionImplement.h>
//#include <NsGui/UIElementData.h>
//#include <NsGui/UIPropertyMetadata.h>
//#include <NsDrawing/Thickness.h>
//#include <NsGui/GradientStopCollection.h>
//#include <NsGui/ContentPropertyMetaData.h>
//#include <NsRender/RenderContext.h>
//#include <NsRender/RenderDevice.h>
//
//#ifdef NS_PLATFORM_WINDOWS_DESKTOP
//typedef unsigned char BYTE;
//#include "NineSliceMask_Opacity.h"
//#endif
//
//#include "GLSLHelpers.h"
//
//
//using namespace Noesis;
//using namespace NoesisApp;
//
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////////////////
//NineSliceMaskBrushShader::NineSliceMaskBrushShader()
//{
//    if (Shader == 0)
//    {
//        ShaderSource shader = { "Noesis_Monochrome_Opacity", Shader::Opacity_Pattern };
//        shader.hlsl = NineSliceMask_Opacity;
//
//        RenderContext* context = RenderContext::Current();
//        Shader = context->CreatePixelShader(shader);
//    }
//
//    mConstants.left = 0.0f;
//    mConstants.top = 0.0f;
//    mConstants.right = 0.0f;
//    mConstants.bottom = 0.0f;
//    mConstants.width = 0.0f;
//    mConstants.height = 0.0f;
//    SetConstantBuffer(&mConstants, sizeof(mConstants));
//
//    SetPixelShader(Shader, BrushShader::Target::Opacity);
//}
//
//////////////////////////////////////////////////////////////////////////////////////////////////////
//NS_BEGIN_COLD_REGION
//
//NS_IMPLEMENT_REFLECTION(NineSliceMaskBrushShader, "NoesisGUIExtensions.NineSliceMaskBrushShader")
//{
//    auto OnThicknessChanged = [](DependencyObject* o, const DependencyPropertyChangedEventArgs& args)
//    {
//        NineSliceMaskBrushShader* this_ = (NineSliceMaskBrushShader*)o;
//        this_->mConstants.left = args.NewValue<Thickness>().left;
//        this_->mConstants.top = args.NewValue<Thickness>().top;
//        this_->mConstants.right = args.NewValue<Thickness>().right;
//        this_->mConstants.bottom = args.NewValue<Thickness>().bottom;
//        this_->InvalidateConstantBuffer();
//    };
//
//    auto OnWidthChanged = [](DependencyObject* o, const DependencyPropertyChangedEventArgs& args)
//    {
//        NineSliceMaskBrushShader* this_ = (NineSliceMaskBrushShader*)o;
//        this_->mConstants.width = args.NewValue<float>();
//        this_->InvalidateConstantBuffer();
//    };
//
//    auto OnHeightChanged = [](DependencyObject* o, const DependencyPropertyChangedEventArgs& args)
//    {
//        NineSliceMaskBrushShader* this_ = (NineSliceMaskBrushShader*)o;
//        this_->mConstants.height = args.NewValue<float>();
//        this_->InvalidateConstantBuffer();
//    };
//
//    UIElementData* data = NsMeta<UIElementData>(TypeOf<SelfClass>());
//    data->RegisterProperty<Thickness>(SlicesProperty, "Slices",
//        UIPropertyMetadata::Create(Thickness(), PropertyChangedCallback(OnThicknessChanged)));
//    data->RegisterProperty<float>(WidthProperty, "Width",
//        UIPropertyMetadata::Create(0.0f, PropertyChangedCallback(OnWidthChanged)));
//    data->RegisterProperty<float>(HeightProperty, "Height",
//        UIPropertyMetadata::Create(0.0f, PropertyChangedCallback(OnHeightChanged)));
//}
//
//NS_END_COLD_REGION
//
//////////////////////////////////////////////////////////////////////////////////////////////////////
//const DependencyProperty* NineSliceMaskBrushShader::SlicesProperty;
//const DependencyProperty* NineSliceMaskBrushShader::WidthProperty;
//const DependencyProperty* NineSliceMaskBrushShader::HeightProperty;
//void* NineSliceMaskBrushShader::Shader;
NineSliceMaskBrushShader.cpp (4,044 bytes)   
NineSliceMaskBrushShader.h (2,155 bytes)   
////////////////////////////////////////////////////////////////////////////////////////////////////
// NoesisGUI - http://www.noesisengine.com
// Copyright (c) 2013 Noesis Technologies S.L. All Rights Reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////


#ifndef __APP_NINESLICEMASKBRUSHSHADER_H__
#define __APP_NINESLICEMASKBRUSHSHADER_H__


#include <NsApp/ShadersApi.h>
#include <NsGui/BrushShader.h>
#include <NsDrawing/Color.h>


namespace Noesis { class DependencyProperty; }

namespace NoesisApp
{

NS_WARNING_PUSH
NS_MSVC_WARNING_DISABLE(4251)

////////////////////////////////////////////////////////////////////////////////////////////////////
/// BrushShader that turns an image into a monochrome color
///
/// .. code-block:: xml
///
///  <StackPanel
///    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
///    xmlns:noesis="clr-namespace:NoesisGUIExtensions"
///    Orientation="Horizontal">
///    <Image Source="Images/tulip.png"/>
///    <Rectangle Width="300" Height="300">
///      <Rectangle.Fill>
///        <ImageBrush ImageSource="Images/tulip.png">
///          <noesis:Brush.Shader>
///            <noesis:MonochromeBrushShader />
///          </noesis:Brush.Shader>
///        </ImageBrush>
///      </Rectangle.Fill>
///    </Rectangle>
///  </StackPanel>
///
/// .. image:: Monochrome.jpg
///
////////////////////////////////////////////////////////////////////////////////////////////////////
class NS_APP_SHADERS_API NineSliceMaskBrushShader final: public Noesis::BrushShader
{
public:
    NineSliceMaskBrushShader();

public:
    static const Noesis::DependencyProperty* SlicesProperty;
    static const Noesis::DependencyProperty* WidthProperty;
    static const Noesis::DependencyProperty* HeightProperty;
    static void* Shader;

private:
    struct Constants
    { 
        float left, top, right, bottom;
        float width, height;
    };

    Constants mConstants;

    NS_DECLARE_REFLECTION(NineSliceMaskBrushShader, BrushShader)
};

NS_WARNING_POP

}

#endif
NineSliceMaskBrushShader.h (2,155 bytes)   

Issue History

Date Modified Username Field Change
2022-04-14 11:12 jsantos New Issue
2022-04-14 11:12 jsantos Assigned To => sfernandez
2022-04-14 11:12 jsantos Status new => assigned
2022-04-14 11:12 jsantos Target Version => 3.1
2022-04-25 17:37 jsantos Note Added: 0007912
2022-04-25 17:38 jsantos Note Edited: 0007912
2022-04-25 17:39 jsantos Note Edited: 0007912
2022-04-25 17:39 jsantos Note Edited: 0007912
2022-07-26 10:08 sfernandez Note Added: 0008031
2022-07-26 10:08 sfernandez Target Version 3.1 => 3.2.0
2023-03-27 12:14 jsantos Target Version 3.2.0 => 3.2
2023-04-26 14:11 jsantos Note Added: 0008462
2023-04-26 14:11 jsantos File Added: NineSliceMask.hlsli
2023-04-26 14:11 jsantos File Added: NineSliceMask_Opacity.hlsl
2023-04-26 14:11 jsantos File Added: NineSliceMaskBrushShader.cpp
2023-04-26 14:11 jsantos File Added: NineSliceMaskBrushShader.h
2024-05-23 19:38 sfernandez Status assigned => resolved
2024-05-23 19:38 sfernandez Resolution open => fixed
2024-05-23 19:38 sfernandez Fixed in Version => 3.2.4
2024-05-23 19:38 sfernandez Target Version 3.2 => 3.2.4