Advertisement
xoofx

Ripple.cpp

Apr 17th, 2012
273
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.33 KB | None | 0 0
  1. //// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. //// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. //// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. //// PARTICULAR PURPOSE.
  5. ////
  6. //// Copyright (c) Microsoft Corporation. All rights reserved
  7.  
  8. #include "pch.h"
  9. #include "Ripple.h"
  10. #define XML(X) TEXT(#X)
  11.  
  12. Ripple::Ripple() :
  13.     m_refCount(1)
  14. {
  15.     m_constants.amplitude = 0;
  16.     m_constants.center = D2D1::Point2F(0,0);
  17.     m_constants.frequency = 0;
  18.     m_constants.phase = 0;
  19.     m_constants.spread = 0;
  20. }
  21.  
  22. HRESULT __stdcall Ripple::CreateRippleImpl(_Outptr_ IUnknown** effectImpl)
  23. {
  24.     // Since the object's refcount is initialized to 1, we don't need to AddRef here.
  25.     *effectImpl = static_cast<ID2D1EffectImpl *>(new Ripple());
  26.  
  27.     if (*effectImpl == nullptr)
  28.     {
  29.         return E_OUTOFMEMORY;
  30.     }
  31.     else
  32.     {
  33.         return S_OK;
  34.     }
  35. }
  36.  
  37. HRESULT Ripple::Register(_In_ ID2D1Factory1* factory)
  38. {
  39.     // The inspectable metadata of an effect is defined in XML. This can be passed in from an external source
  40.     // as well, however for simplicity we just inline the XML.
  41.     static PCWSTR pszXml =
  42.         XML(
  43.         <?xml version='1.0'?>
  44.         <Effect>
  45.             <!-- System Properties -->
  46.             <Property name='DisplayName' type='string' value='Ripple'/>
  47.             <Property name='Author' type='string' value='Microsoft Corporation'/>
  48.             <Property name='Category' type='string' value='Stylize'/>
  49.             <Property name='Description' type='string' value='Adds a ripple effect that can be animated'/>
  50.  
  51.             <Inputs>
  52.                 <Input name='Source'/>
  53.             </Inputs>
  54.  
  55.             <!-- Custom Properties go here -->
  56.             <Property name='Frequency' type='float'>
  57.                 <Property name='DisplayName' type='string' value='Frequency'/>
  58.                 <Property name='Min' type='float' value='0.0' />
  59.                 <Property name='Max' type='float' value='1000.0' />
  60.                 <Property name='Default' type='float' value='0.0' />
  61.             </Property>
  62.  
  63.             <Property name='Phase' type='float'>
  64.                 <Property name='DisplayName' type='string' value='Phase'/>
  65.                 <Property name='Min' type='float' value='-100.0' />
  66.                 <Property name='Max' type='float' value='100.0' />
  67.                 <Property name='Default' type='float' value='0.0' />
  68.             </Property>
  69.  
  70.             <Property name='Amplitude' type='float'>
  71.                 <Property name='DisplayName' type='string' value='Amplitude'/>
  72.                 <Property name='Min' type='float' value='0.0001' />
  73.                 <Property name='Max' type='float' value='1000.0' />
  74.                 <Property name='Default' type='float' value='0.0' />
  75.             </Property>
  76.  
  77.             <Property name='Spread' type='float'>
  78.                 <Property name='DisplayName' type='string' value='Spread'/>
  79.                 <Property name='Min' type='float' value='0.0001' />
  80.                 <Property name='Max' type='float' value='1000.0' />
  81.                 <Property name='Default' type='float' value='0.0' />
  82.             </Property>
  83.  
  84.             <Property name='Center' type='vector2'>
  85.                 <Property name='DisplayName' type='string' value='Center'/>
  86.                 <Property name='Min' type='vector2' value='(-2000.0, -2000.0)' />
  87.                 <Property name='Max' type='vector2' value='(2000.0, 2000.0)' />
  88.                 <Property name='Default' type='vector2' value='(0.0, 0.0)' />
  89.             </Property>
  90.         </Effect>
  91.         );
  92.  
  93.     // This defines the bindings from specific properties to the callback functions
  94.     // on the class that ID2D1Effect::SetValue() & GetValue() will call.
  95.     static const D2D1_PROPERTY_BINDING bindings[] =
  96.     {
  97.         D2D1_VALUE_TYPE_BINDING(L"Frequency", &SetFrequency, &GetFrequency),
  98.         D2D1_VALUE_TYPE_BINDING(L"Phase", &SetPhase, &GetPhase),
  99.         D2D1_VALUE_TYPE_BINDING(L"Amplitude", &SetAmplitude, &GetAmplitude),
  100.         D2D1_VALUE_TYPE_BINDING(L"Spread", &SetSpread, &GetSpread),
  101.         D2D1_VALUE_TYPE_BINDING(L"Center", &SetCenter, &GetCenter),
  102.     };
  103.  
  104.     // This registers the effect with the factory, which will make the effect
  105.     // instantiatable.
  106.     return factory->RegisterEffectFromString(
  107.         CLSID_CustomRippleEffect,
  108.         pszXml,
  109.         bindings,
  110.         ARRAYSIZE(bindings),
  111.         CreateRippleImpl
  112.         );
  113. }
  114.  
  115. HRESULT __stdcall Ripple::Initialize(
  116.     _In_ ID2D1EffectContext* contextInternal,
  117.     _In_ ID2D1TransformGraph* transformGraph
  118.     )
  119. {
  120.     // The graph consists of a single transform. In fact, this class is the transform,
  121.     // reducing the complexity of implementing an effect when all we need to
  122.     // do is use a single pixel shader.
  123.     HRESULT hr = transformGraph->SetSingleTransformNode(this);
  124.  
  125.     // This loads the shader into the Direct2D image effects system and associates it with the GUID passed in.
  126.     // If this method is called more than once (say by other instances of the effect) with the same GUID,
  127.     // the system will simply do nothing, ensuring that only one instance of a shader is stored regardless of how
  128.     // many time it is used.
  129.     if (SUCCEEDED(hr))
  130.     {
  131.         BasicReaderWriter^ reader = ref new BasicReaderWriter();
  132.         auto data = reader->ReadData("Ripple.cso");
  133.  
  134.         hr = contextInternal->LoadPixelShader(GUID_RipplePixelShader, data->Data, data->Length);
  135.     }
  136.  
  137.     return hr;
  138. }
  139.  
  140. HRESULT Ripple::SetFrequency(float frequency)
  141. {
  142.     // Limit to the published possible values in the XML.
  143.     m_constants.frequency = Clamp(frequency, 0.0f, 1000.0f);
  144.     UpdateConstants();
  145.     return S_OK;
  146. }
  147.  
  148. float Ripple::GetFrequency() const
  149. {
  150.     return m_constants.frequency;
  151. }
  152.  
  153. HRESULT Ripple::SetPhase(float phase)
  154. {
  155.     // Limit to the published possible values in the XML.
  156.     m_constants.phase = Clamp(phase, -100.0f, 100.0f);
  157.     return S_OK;
  158. }
  159.  
  160. float Ripple::GetPhase() const
  161. {
  162.     return m_constants.phase;
  163. }
  164.  
  165. HRESULT Ripple::SetAmplitude(float amplitude)
  166. {
  167.     // Limit to the published possible values in the XML.
  168.     m_constants.amplitude = Clamp(amplitude, 0.0001f, 1000.0f);
  169.     return S_OK;
  170. }
  171.  
  172. float Ripple::GetSpread() const
  173. {
  174.     return m_constants.spread;
  175. }
  176.  
  177. HRESULT Ripple::SetSpread(float spread)
  178. {
  179.     // Limit to the published possible values in the XML.
  180.     m_constants.spread = Clamp(spread, 0.0001f, 1000.0f);
  181.     return S_OK;
  182. }
  183.  
  184. float Ripple::GetAmplitude() const
  185. {
  186.     return m_constants.amplitude;
  187. }
  188.  
  189. HRESULT Ripple::SetCenter(D2D1_POINT_2F center)
  190. {
  191.     // The valid range is all possible point positions, so no clamping is needed.
  192.     m_constants.center = center;
  193.     return S_OK;
  194. }
  195.  
  196. D2D1_POINT_2F Ripple::GetCenter() const
  197. {
  198.     return m_constants.center;
  199. }
  200.  
  201. void Ripple::UpdateConstants()
  202. {
  203.     // Only update the constant buffer if the pixel shader has been initialized.
  204.     if(m_drawInfo != nullptr)
  205.     {
  206.         m_drawInfo->SetPixelShaderConstantBuffer(reinterpret_cast<BYTE*>(&m_constants), sizeof(m_constants));
  207.     }
  208. }
  209.  
  210. HRESULT __stdcall Ripple::PrepareForRender(D2D1_CHANGE_TYPE changeType)
  211. {
  212.     UpdateConstants();
  213.     return S_OK;
  214. }
  215.  
  216. // SetGraph is only called when the number of inputs changes. This never happens as we publish this effect
  217. // as a single input effect.
  218. HRESULT __stdcall Ripple::SetGraph(_In_ ID2D1TransformGraph* graph)
  219. {
  220.     return E_NOTIMPL;
  221. }
  222.  
  223. // Called to assign a new render info class, which is used to inform D2D on
  224. // how to set the state of the GPU.
  225. HRESULT __stdcall Ripple::SetDrawInfo(_In_ ID2D1DrawInfo* drawInfo)
  226. {
  227.     m_drawInfo = drawInfo;
  228.  
  229.    HRESULT hr = m_drawInfo->SetPixelShader(GUID_RipplePixelShader);
  230.  
  231.     if (SUCCEEDED(hr))
  232.     {
  233.         D2D1_INPUT_DESCRIPTION inputDesc;
  234.         inputDesc.filter = D2D1_FILTER_MIN_MAG_LINEAR_MIP_POINT;
  235.         inputDesc.levelOfDetailCount = 1;
  236.  
  237.         hr = m_drawInfo->SetInputDescription(0, inputDesc);
  238.     }
  239.  
  240.     return hr;
  241. }
  242.  
  243. // Calculates the mapping between the output and input rects. In this case,
  244. // we want to request an expanded region to account for pixels that the ripple
  245. // may need outside of the bounds of the destination.
  246. HRESULT __stdcall Ripple::MapOutputRectToInputRects(
  247.     const D2D1_RECT_L* outputRect,
  248.     D2D1_RECT_L* inputRects,
  249.     UINT32 inputRectCount
  250.     ) const
  251. {
  252.     long expansion = static_cast<long>(Round(m_constants.amplitude));
  253.  
  254.     // This effect has exactly one input, so if there is more than one input rect,
  255.     // something is wrong.
  256.     if (inputRectCount != 1)
  257.     {
  258.         return E_INVALIDARG;
  259.     }
  260.  
  261.     // Expand the rect out by the amplitude of the ripple animation.
  262.     inputRects[0].left    = outputRect->left   - expansion;
  263.     inputRects[0].top     = outputRect->top    - expansion;
  264.     inputRects[0].right   = outputRect->right  + expansion;
  265.     inputRects[0].bottom  = outputRect->bottom + expansion;
  266.  
  267.     return S_OK;
  268. }
  269.  
  270. HRESULT __stdcall Ripple::MapInputRectsToOutputRect(
  271.     _In_reads_(inputRectsCount) const D2D1_RECT_L* inputRects,
  272.     UINT inputRectsCount,
  273.     D2D1_RECT_L* outputRect
  274.     ) const
  275. {
  276.     // This effect has exactly one input, so if there is more than one input rect,
  277.     // something is wrong.
  278.     if (inputRectsCount != 1)
  279.     {
  280.         return E_INVALIDARG;
  281.     }
  282.  
  283.     *outputRect = inputRects[0];
  284.     return S_OK;
  285. }
  286.  
  287. HRESULT __stdcall Ripple::SetInputRects(
  288.     _In_reads_(inputRectsCount) const D2D1_RECT_L* inputRects,
  289.     UINT inputRectsCount)
  290. {
  291.     // The size of the inputRect corresponds with the size of the incoming image. Since the input size
  292.     // of the image does not affect how this custom effect operates, no operation is necessary.
  293.  
  294.     return S_OK;
  295. }
  296.  
  297. UINT32 __stdcall Ripple::GetInputCount() const
  298. {
  299.     return 1;
  300. }
  301.  
  302. // These methods should increment or decrement the refcount using
  303. // interlocked functions to ensure the interface can be using
  304. // in multi-threaded applications.
  305. ULONG __stdcall Ripple::AddRef()
  306. {
  307.     return InterlockedIncrement(&m_refCount);
  308. }
  309.  
  310. ULONG __stdcall Ripple::Release()
  311. {
  312.     ULONG refCount = InterlockedDecrement(&m_refCount);
  313.  
  314.     if (refCount == 0)
  315.     {
  316.         delete this;
  317.     }
  318.  
  319.     return m_refCount;
  320. }
  321.  
  322. // This enables the stack of parent interfaces to be queried. In the instance
  323. // of the Ripple interface, this method simply enables the developer
  324. // to cast a Ripple instance to an ID2D1EffectImpl or IUnknown instance.
  325. HRESULT __stdcall Ripple::QueryInterface(
  326.     _In_ REFIID riid,
  327.     _Outptr_ void** output
  328.     )
  329. {
  330.     *output = nullptr;
  331.     HRESULT hr = S_OK;
  332.  
  333.     if (riid == __uuidof(ID2D1EffectImpl))
  334.     {
  335.         *output = reinterpret_cast<ID2D1EffectImpl *>(this);
  336.     }
  337.     else if (riid == __uuidof(ID2D1DrawTransform))
  338.     {
  339.         *output = static_cast<ID2D1DrawTransform *>(this);
  340.     }
  341.     else if (riid == __uuidof(ID2D1Transform))
  342.     {
  343.         *output = static_cast<ID2D1Transform *>(this);
  344.     }
  345.     else if (riid == __uuidof(ID2D1TransformNode))
  346.     {
  347.         *output = static_cast<ID2D1TransformNode *>(this);
  348.     }
  349.     else if (riid == __uuidof(IUnknown))
  350.     {
  351.         *output = reinterpret_cast<IUnknown *>(this);
  352.     }
  353.     else
  354.     {
  355.         hr = E_NOINTERFACE;
  356.     }    
  357.  
  358.     if (*output != nullptr)
  359.     {
  360.         AddRef();
  361.     }
  362.  
  363.     return hr;
  364. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement