Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
- //// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- //// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
- //// PARTICULAR PURPOSE.
- ////
- //// Copyright (c) Microsoft Corporation. All rights reserved
- #include "pch.h"
- #include "Ripple.h"
- #define XML(X) TEXT(#X)
- Ripple::Ripple() :
- m_refCount(1)
- {
- m_constants.amplitude = 0;
- m_constants.center = D2D1::Point2F(0,0);
- m_constants.frequency = 0;
- m_constants.phase = 0;
- m_constants.spread = 0;
- }
- HRESULT __stdcall Ripple::CreateRippleImpl(_Outptr_ IUnknown** effectImpl)
- {
- // Since the object's refcount is initialized to 1, we don't need to AddRef here.
- *effectImpl = static_cast<ID2D1EffectImpl *>(new Ripple());
- if (*effectImpl == nullptr)
- {
- return E_OUTOFMEMORY;
- }
- else
- {
- return S_OK;
- }
- }
- HRESULT Ripple::Register(_In_ ID2D1Factory1* factory)
- {
- // The inspectable metadata of an effect is defined in XML. This can be passed in from an external source
- // as well, however for simplicity we just inline the XML.
- static PCWSTR pszXml =
- XML(
- <?xml version='1.0'?>
- <Effect>
- <!-- System Properties -->
- <Property name='DisplayName' type='string' value='Ripple'/>
- <Property name='Author' type='string' value='Microsoft Corporation'/>
- <Property name='Category' type='string' value='Stylize'/>
- <Property name='Description' type='string' value='Adds a ripple effect that can be animated'/>
- <Inputs>
- <Input name='Source'/>
- </Inputs>
- <!-- Custom Properties go here -->
- <Property name='Frequency' type='float'>
- <Property name='DisplayName' type='string' value='Frequency'/>
- <Property name='Min' type='float' value='0.0' />
- <Property name='Max' type='float' value='1000.0' />
- <Property name='Default' type='float' value='0.0' />
- </Property>
- <Property name='Phase' type='float'>
- <Property name='DisplayName' type='string' value='Phase'/>
- <Property name='Min' type='float' value='-100.0' />
- <Property name='Max' type='float' value='100.0' />
- <Property name='Default' type='float' value='0.0' />
- </Property>
- <Property name='Amplitude' type='float'>
- <Property name='DisplayName' type='string' value='Amplitude'/>
- <Property name='Min' type='float' value='0.0001' />
- <Property name='Max' type='float' value='1000.0' />
- <Property name='Default' type='float' value='0.0' />
- </Property>
- <Property name='Spread' type='float'>
- <Property name='DisplayName' type='string' value='Spread'/>
- <Property name='Min' type='float' value='0.0001' />
- <Property name='Max' type='float' value='1000.0' />
- <Property name='Default' type='float' value='0.0' />
- </Property>
- <Property name='Center' type='vector2'>
- <Property name='DisplayName' type='string' value='Center'/>
- <Property name='Min' type='vector2' value='(-2000.0, -2000.0)' />
- <Property name='Max' type='vector2' value='(2000.0, 2000.0)' />
- <Property name='Default' type='vector2' value='(0.0, 0.0)' />
- </Property>
- </Effect>
- );
- // This defines the bindings from specific properties to the callback functions
- // on the class that ID2D1Effect::SetValue() & GetValue() will call.
- static const D2D1_PROPERTY_BINDING bindings[] =
- {
- D2D1_VALUE_TYPE_BINDING(L"Frequency", &SetFrequency, &GetFrequency),
- D2D1_VALUE_TYPE_BINDING(L"Phase", &SetPhase, &GetPhase),
- D2D1_VALUE_TYPE_BINDING(L"Amplitude", &SetAmplitude, &GetAmplitude),
- D2D1_VALUE_TYPE_BINDING(L"Spread", &SetSpread, &GetSpread),
- D2D1_VALUE_TYPE_BINDING(L"Center", &SetCenter, &GetCenter),
- };
- // This registers the effect with the factory, which will make the effect
- // instantiatable.
- return factory->RegisterEffectFromString(
- CLSID_CustomRippleEffect,
- pszXml,
- bindings,
- ARRAYSIZE(bindings),
- CreateRippleImpl
- );
- }
- HRESULT __stdcall Ripple::Initialize(
- _In_ ID2D1EffectContext* contextInternal,
- _In_ ID2D1TransformGraph* transformGraph
- )
- {
- // The graph consists of a single transform. In fact, this class is the transform,
- // reducing the complexity of implementing an effect when all we need to
- // do is use a single pixel shader.
- HRESULT hr = transformGraph->SetSingleTransformNode(this);
- // This loads the shader into the Direct2D image effects system and associates it with the GUID passed in.
- // If this method is called more than once (say by other instances of the effect) with the same GUID,
- // the system will simply do nothing, ensuring that only one instance of a shader is stored regardless of how
- // many time it is used.
- if (SUCCEEDED(hr))
- {
- BasicReaderWriter^ reader = ref new BasicReaderWriter();
- auto data = reader->ReadData("Ripple.cso");
- hr = contextInternal->LoadPixelShader(GUID_RipplePixelShader, data->Data, data->Length);
- }
- return hr;
- }
- HRESULT Ripple::SetFrequency(float frequency)
- {
- // Limit to the published possible values in the XML.
- m_constants.frequency = Clamp(frequency, 0.0f, 1000.0f);
- UpdateConstants();
- return S_OK;
- }
- float Ripple::GetFrequency() const
- {
- return m_constants.frequency;
- }
- HRESULT Ripple::SetPhase(float phase)
- {
- // Limit to the published possible values in the XML.
- m_constants.phase = Clamp(phase, -100.0f, 100.0f);
- return S_OK;
- }
- float Ripple::GetPhase() const
- {
- return m_constants.phase;
- }
- HRESULT Ripple::SetAmplitude(float amplitude)
- {
- // Limit to the published possible values in the XML.
- m_constants.amplitude = Clamp(amplitude, 0.0001f, 1000.0f);
- return S_OK;
- }
- float Ripple::GetSpread() const
- {
- return m_constants.spread;
- }
- HRESULT Ripple::SetSpread(float spread)
- {
- // Limit to the published possible values in the XML.
- m_constants.spread = Clamp(spread, 0.0001f, 1000.0f);
- return S_OK;
- }
- float Ripple::GetAmplitude() const
- {
- return m_constants.amplitude;
- }
- HRESULT Ripple::SetCenter(D2D1_POINT_2F center)
- {
- // The valid range is all possible point positions, so no clamping is needed.
- m_constants.center = center;
- return S_OK;
- }
- D2D1_POINT_2F Ripple::GetCenter() const
- {
- return m_constants.center;
- }
- void Ripple::UpdateConstants()
- {
- // Only update the constant buffer if the pixel shader has been initialized.
- if(m_drawInfo != nullptr)
- {
- m_drawInfo->SetPixelShaderConstantBuffer(reinterpret_cast<BYTE*>(&m_constants), sizeof(m_constants));
- }
- }
- HRESULT __stdcall Ripple::PrepareForRender(D2D1_CHANGE_TYPE changeType)
- {
- UpdateConstants();
- return S_OK;
- }
- // SetGraph is only called when the number of inputs changes. This never happens as we publish this effect
- // as a single input effect.
- HRESULT __stdcall Ripple::SetGraph(_In_ ID2D1TransformGraph* graph)
- {
- return E_NOTIMPL;
- }
- // Called to assign a new render info class, which is used to inform D2D on
- // how to set the state of the GPU.
- HRESULT __stdcall Ripple::SetDrawInfo(_In_ ID2D1DrawInfo* drawInfo)
- {
- m_drawInfo = drawInfo;
- HRESULT hr = m_drawInfo->SetPixelShader(GUID_RipplePixelShader);
- if (SUCCEEDED(hr))
- {
- D2D1_INPUT_DESCRIPTION inputDesc;
- inputDesc.filter = D2D1_FILTER_MIN_MAG_LINEAR_MIP_POINT;
- inputDesc.levelOfDetailCount = 1;
- hr = m_drawInfo->SetInputDescription(0, inputDesc);
- }
- return hr;
- }
- // Calculates the mapping between the output and input rects. In this case,
- // we want to request an expanded region to account for pixels that the ripple
- // may need outside of the bounds of the destination.
- HRESULT __stdcall Ripple::MapOutputRectToInputRects(
- const D2D1_RECT_L* outputRect,
- D2D1_RECT_L* inputRects,
- UINT32 inputRectCount
- ) const
- {
- long expansion = static_cast<long>(Round(m_constants.amplitude));
- // This effect has exactly one input, so if there is more than one input rect,
- // something is wrong.
- if (inputRectCount != 1)
- {
- return E_INVALIDARG;
- }
- // Expand the rect out by the amplitude of the ripple animation.
- inputRects[0].left = outputRect->left - expansion;
- inputRects[0].top = outputRect->top - expansion;
- inputRects[0].right = outputRect->right + expansion;
- inputRects[0].bottom = outputRect->bottom + expansion;
- return S_OK;
- }
- HRESULT __stdcall Ripple::MapInputRectsToOutputRect(
- _In_reads_(inputRectsCount) const D2D1_RECT_L* inputRects,
- UINT inputRectsCount,
- D2D1_RECT_L* outputRect
- ) const
- {
- // This effect has exactly one input, so if there is more than one input rect,
- // something is wrong.
- if (inputRectsCount != 1)
- {
- return E_INVALIDARG;
- }
- *outputRect = inputRects[0];
- return S_OK;
- }
- HRESULT __stdcall Ripple::SetInputRects(
- _In_reads_(inputRectsCount) const D2D1_RECT_L* inputRects,
- UINT inputRectsCount)
- {
- // The size of the inputRect corresponds with the size of the incoming image. Since the input size
- // of the image does not affect how this custom effect operates, no operation is necessary.
- return S_OK;
- }
- UINT32 __stdcall Ripple::GetInputCount() const
- {
- return 1;
- }
- // These methods should increment or decrement the refcount using
- // interlocked functions to ensure the interface can be using
- // in multi-threaded applications.
- ULONG __stdcall Ripple::AddRef()
- {
- return InterlockedIncrement(&m_refCount);
- }
- ULONG __stdcall Ripple::Release()
- {
- ULONG refCount = InterlockedDecrement(&m_refCount);
- if (refCount == 0)
- {
- delete this;
- }
- return m_refCount;
- }
- // This enables the stack of parent interfaces to be queried. In the instance
- // of the Ripple interface, this method simply enables the developer
- // to cast a Ripple instance to an ID2D1EffectImpl or IUnknown instance.
- HRESULT __stdcall Ripple::QueryInterface(
- _In_ REFIID riid,
- _Outptr_ void** output
- )
- {
- *output = nullptr;
- HRESULT hr = S_OK;
- if (riid == __uuidof(ID2D1EffectImpl))
- {
- *output = reinterpret_cast<ID2D1EffectImpl *>(this);
- }
- else if (riid == __uuidof(ID2D1DrawTransform))
- {
- *output = static_cast<ID2D1DrawTransform *>(this);
- }
- else if (riid == __uuidof(ID2D1Transform))
- {
- *output = static_cast<ID2D1Transform *>(this);
- }
- else if (riid == __uuidof(ID2D1TransformNode))
- {
- *output = static_cast<ID2D1TransformNode *>(this);
- }
- else if (riid == __uuidof(IUnknown))
- {
- *output = reinterpret_cast<IUnknown *>(this);
- }
- else
- {
- hr = E_NOINTERFACE;
- }
- if (*output != nullptr)
- {
- AddRef();
- }
- return hr;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement