dev.nlited.com

>>

Multiple Sources

<<<< prev
next >>>>

2022-12-16 16:39:09 chip Page 2468 📢 PUBLIC

December 15 2022

So far everything has taken a single input, twiddled the pixels, and output pixels 1:1. Now I want to merge multiple sources into a single output. This is the final requirement for my Fog of War effect.

Figuring this out took a while ...

Adding a second source to the XML descriptor still works, so the second source is optional.

I have several questions:

1635: I have spent about four hours trying to add a second input. There are no errors, but all I see are black pixels. I'm not sure if D2DGetInput(1) is failing to read the pixels on the GPU or if pEffect->SetInput(1,pbmSrc2) is failing to add the second source.

1900: Signs of hope? I did something, not sure what, that caused SetGraph() to be called. I believe this is a signal that the second input is being connected. But still no second source appearing in the output. Going to sleep on it.

December 16 2022

I am going to carve ID2D1DrawTransform out of MyEffect into its own stand-alone class, on the hunch that maybe I need multiple transforms.

After an hour or so, MyEffect is "working" again with an external MyTransform. "Working" means I see only one input, but it runs.

I am beginning to suspect the call to SetSingleTransformNode() ... I replaced this with the sequence AddNode(), SetOutputNode(), ConnectToEffectInput(), ConnectToEffectInput().

Progress! I am now seeing all of Source1 and part of Source2! I suspect this may have something to do with the Map...Rect() functions.

0900: SUCCESS!!! I needed to copy all the rectangles, I was only copying the first one. I now see the merged output of both inputs!

PxlShader

I suspect carving out the DrawTransform was not necessary after all, and having them separate causes some awkward code in PrepareForRender(). (The Effect has the constant parameters, but the Transform has the interface to transfer the constants to the shader. The forced me to create a way to have MyEffect::PrepareForRender() call MyTransform to perform the transfer.) I am going to spend a few minutes undoing that carve out and see if everything still works.

0930: That was quick. Using a merged ID2D1EffectImpl / ID2D1DrawTransform works, now that I know how to assemble the graph properly. Now I can go back and try to document the changes...

Adding a Second Input

My effect is going to take two sources and output the average pixel. Going from a single source to two is a big change, but going from two to three or more should just be a matter of changing MAX_INPUT. I read somewhere that shaders have an upper limit of 8 inputs. (Not sure about that number.)

My effect will still be a single transform, so I can continue to merge both ID2D1EffectImpl and ID2D1DrawTransform into a single class. Each input will have its own input rectangle. The only change to the MyEffect class declaration is setting a limit for the number of inputs and converting rIn to an array.


MyEffect declaration: #define MAX_INPUT 2 class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform { public: //EffectImpl static HRESULT Register(_In_ ID2D1Factory1 *pFactory); static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect); IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface); IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); }; IFACEMETHODIMP_(ULONG) Release(void); IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph); IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type); IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph); //DrawTransform IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw); IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const; IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque); IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const; IFACEMETHODIMP_(UINT32) GetInputCount(void) const; //Added HRESULT SetTint(UINT32 Clr); UINT32 GetTint(void) const; private: MyEffect(void); ~MyEffect(void); // Data DWORD Signature; LONG ctReference; ID2D1EffectContext *pCtx; ID2D1DrawInfo *pDraw; UINT ctInput; D2D1_RECT_L rIn[MAX_INPUT]; struct ShaderConstant_s { float tint[4]; } Constants; };

The XML description of the effect in Register() needs to change to allow two inputs. Note that both Inputs:maximum and the number of Input clauses need to match.

MyEffect::Register(): HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) { HRESULT WinErr= S_OK; static const PCWSTR pszXml = L"<?xml version='1.0'?>\r\n" L"<Effect>\r\n" L" <!-- System Properties -->\r\n" L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n" L" <Property name='Author' type='string' value='nlited systems'/>\r\n" L" <Property name='Category' type='string' value='Experimental'/>\r\n" L" <Property name='Description' type='string' value='My first effect.'/>\r\n" L" <Inputs minimum='0' maximum='2'>\r\n" // Source must be specified. L" <Input name='Source1'/>\r\n" L" <Input name='Source2'/>\r\n" L" </Inputs>\r\n" L" <!-- Custom Properties go here. -->\r\n" L" <Property name='Tint' type='uint32'>\r\n" L" <Property name='DisplayName' type='string' value='Tint'/>\r\n" L" <Property name='Default' type='uint32' value='0'/>\r\n" L" </Property>\r\n" L"</Effect>\r\n" ; static const D2D1_PROPERTY_BINDING Bindings[]= { D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint) }; if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) { Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr); } return(WinErr); }

Initialize() needs to change, I can no longer call SetSingleTransformNode(). This confused me for a long time, I thought it should be ok to set additional inputs after creating the single node. It seems I cannot make any changes after calling SetSingleTransformNode(). Multiple inputs requires configuring the graph manually instead. I was further confused by the somewhat terse and ambiguous description of ConnectToEffectInput(). Being able to specify both the EffectInput and the NodeInput allows me to cross-wire the inputs, but the typical usage is to connect them directly; ie use EffectInput == NodeInput. I need to call for each input, 0 and 1.

MyEffect::Initialize(): HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) { HRESULT WinErr= S_OK; ID3DBlob *pCode= 0; ID3DBlob *pError= 0; pCtx= _pCtx; if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"S:\\Src\\HQ\\Dev\\SB\\Chip\\Bugs\\BugsV1\\Out\\Winx64Debug\\FirstShader.cso",&pCode))) { Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr); } else { ctInput= 2; Print(PRINT_INFO,"MyEffect:Initialize: OK."); } SafeRelease(pCode); SafeRelease(pError); return(WinErr); }

Note: This all happens in Initialize(), not in response to the app calling pEffect->SetInput() as I originally expected. There is a bit of a disconnect here, because MyEffect has to assume there are always 2 inputs. There is no notification when the app sets them. In fact, if the app fails to connect the second input MyEffect will never know, but the pdcDraw->EndDraw() will fail with a mysterious "0x8899001E: There was a configuration error in the graph." This behavior is unfortunate because it means I cannot be flexible in the number of inputs MyEffect will accept. If I want to average 2 or 3 sources, I have to create two dedicated effects, one that handles 2 sources and another to handle 3. GetInputCount() must return 2 in one case and 3 in the other. And if the app supplies only 2 sources for the 3-source effect, the Draw() will fail. (pEffect->SetInputCount() seems to be completely feckless.)

SetGraph() is still never called. I believe it is only called if another transform node is added to the graph. MyEffect is still a single transform, just now with multiple inputs.

PrepareForRender() and SetDrawInfo() remain the same. When I carved out the ID2D1DrawTransform into its own class, I ran into a bit of a Catch-22 here: ID2D1EffectImpl::PrepareForRender() is the prompt to transfer the constant parameters to the shader, but ID2D1DrawTransform::SetDrawInfo() is provided the ID2D1DrawInfo interface needed to perform the transfer. This required creating a duplicate MyTransform::PrepareForRender() that is called from MyEffect::PrepareForRender(). This seemed a bit silly and was another point in favor of keeping MyEffect as an amalgam of both ID2D1EffectImpl and ID2D1DrawTransform.

MapOutputRectToInputRects() and MapInputRectsToOutputRect() now need to handle multiple input rectangles. This became obvious when I finally sorted out the graph creation in Initialize() and saw the second source was being truncated. I am still not 100% clear on exactly what these functions are really supposed to do, but copying the rectangles seems to work.

This may work only because both pbmSrc1 and pbmSrc2 happen to be the same size.

MyEffect::MapRects: HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const { HRESULT WinErr= S_OK; //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn); if(ctIn==0) { Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?"); } else if(ctIn>MAX_INPUT) { Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn); WinErr= E_INVALIDARG; } else if(ctIn>0) { prIn[0]= *prOut; for(UINT n1=1;n1<ctIn;n1++) { prIn[n1]= *prOut; } } return(WinErr); } IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) { HRESULT WinErr= S_OK; //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn); if(ctIn==0) { Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?"); } else if(ctIn>MAX_INPUT) { Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn); WinErr= E_INVALIDARG; } else if(ctIn>0) { *prOut= rIn[0]= prIn[0]; for(UINT n1=1;n1<ctIn;n1++) { rIn[n1]= prIn[n1]; } Zero(*prOutOpaque); } return(WinErr); }

MapInvalidRect() remains the same.

GetInputCount() needs to return the expected number of inputs, not the number currently connected.

MyEffect::GetInputCount(): IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const { return(MAX_INPUT); }

MyEffect now supports (and expects) MAX_INPUT (2) inputs.

My app needs to provide two sources, not just one. PxlShader::DrawCreate() needs to create two source bitmaps, pbmSrc1 and pbmSrc2.

PxlShader declaration: class PxlShader { ... private: ... ID2D1Bitmap1 *pbmSrc1; ID2D1Bitmap1 *pbmSrc2; }; int PxlShader::DrawCreate(void) { ... } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); } return(Err); }

And DrawUpdate() continues to become ever more complex. Now I need to draw unique shapes into the two source bitmaps, something I can easily recognize. pbmSrc1 will contain a goldenrod rectangle, pbmSrc2 a forest green circle, and they should partially overlap in the merged output. pbmSrc2 is added as the second input to the effect.

PxlShader::DrawUpdate(): int PxlShader::DrawUpdate(void) { int Err= ERR_OK; HRESULT WinErr; pdcDraw->BeginDraw(); pdcDraw->SetTransform(Matrix3x2F::Identity()); pdcDraw->SetTarget(pbmSrc1); pdcDraw->Clear(ColorF(ColorF::Black,0)); D2D1_RECT_F box= { 0,0,80,60 }; pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod))); pdcDraw->SetTarget(pbmSrc2); pdcDraw->Clear(ColorF(ColorF::Black,0)); D2D1_ELLIPSE dot= { {50,50}, 50,50 }; pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen))); pdcDraw->SetTarget(pbmImg); pdcDraw->Clear(ColorF(ColorF::Black,0)); pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y))); pEffect->SetInput(0,pbmSrc1); pEffect->SetInput(1,pbmSrc2); pdcDraw->DrawImage(pEffect); if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) { Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr); ReleaseEverything(); } return(Err); }

At one point I was calling pEffect->SetInputCount(2) but this seemed to have no effect whatsoever.

And finally the shader. I need to have it do something that will make both inputs obvious in the output: An average of the two pixels.

FirstShader.hlsl: #define D2D_INPUT_COUNT 2 #include "d2d1effecthelpers.hlsli" cbuffer constants: register(b0) { float4 tint:COLOR; }; D2D_PS_ENTRY(main) { float4 color; float4 color0= D2DGetInput(0); float4 color1= D2DGetInput(1); color= (color0+color1)/2; return color; } //EOF: FIRSTSHADER.HLSL

D2DGetInput(n) will retrieve the current pixel from input #n. If there is no input #n, it will return a black pixel without any error. This led to a lot of confusion about whether the input was missing or the shader was failing to access it. Not knowing the difference wasted a couple hours yesterday.

Now I should see both the goldenrod box and the green circle, with the overlap being some sort of yellowish-green.

PxlShader

The non-overlap regions are dark because I am averaging in the black pixels. I can fix that...

Shader2: #define D2D_INPUT_COUNT 2 #include "d2d1effecthelpers.hlsli" cbuffer constants: register(b0) { float4 tint:COLOR; }; D2D_PS_ENTRY(main) { float4 color; float4 color0= D2DGetInput(0); float4 color1= D2DGetInput(1); if(color0.a==0) { color= color1; } else if(color1.a==0) { color= color0; } else { color= (color0+color1)/2; } return color; } //EOF: FIRSTSHADER.HLSL

PxlShader

Success! I now know how to merge two source bitmaps into a single output image.

The complete PxlShader app:

PxlShader.cpp: /*************************************************************************/ /** PxlShader.cpp: Minimal code to run a pixel shader. **/ /** (C)2022 nlited systems, cmd **/ /*************************************************************************/ #include <Windows.h> #include <d3d11_1.h> #include <d2d1.h> #include <d2d1_1.h> #include <d2d1helper.h> #include <d2d1effectauthor.h> #include <d2d1effecthelpers.h> #include <d3dcompiler.h> #include "Handles.h" #include "ChipLib.h" #pragma comment(lib,"D3D11.lib") #pragma comment(lib,"D2D1.lib") #pragma comment(lib,"DXGI.lib") #pragma comment(lib,"d3dcompiler.lib") #pragma message(__FILE__": Optimizer disabled.") #pragma optimize("",off) #define SIGNATURE_PXLSHADER 0xCD190001 #define SIGNATURE_MYEFFECT 0xCD190002 #define SIGNATURE_MYTRANSFORM 0xCD190003 using namespace D2D1; typedef D2D1_POINT_2F POINT2D; HINSTANCE ghInst; DWORD DbgFilter; static const WCHAR ClassName[]= { L"PxlShader" }; // {D8255497-025E-4D3F-A4DF-5C25306F67AC} static const GUID CLSID_MyEffect = { 0xd8255497, 0x25e, 0x4d3f, { 0xa4, 0xdf, 0x5c, 0x25, 0x30, 0x6f, 0x67, 0xac } }; // {2BCB702A-4F42-44D0-B8ED-4E9F9FC7A905} static const GUID GUID_MyPixelShader = { 0x2bcb702a, 0x4f42, 0x44d0, { 0xb8, 0xed, 0x4e, 0x9f, 0x9f, 0xc7, 0xa9, 0x5 } }; #define SafeRelease(pInterface) { if(pInterface && pInterface->Release()==0) pInterface= 0; } //Auto-destruct solid brush. class D2Brush { public: D2Brush(ID2D1RenderTarget *pRT, const D2D1_COLOR_F &clr) { pRT->CreateSolidColorBrush(clr,&pbrBrush); }; ~D2Brush(void) { pbrBrush->Release(); } operator ID2D1Brush *() { return(static_cast<ID2D1Brush*>(pbrBrush)); }; // This lets me use the object as the parameter to the various RenderTarget functions. ID2D1SolidColorBrush *pbrBrush; }; #define MAX_INPUT 2 class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform { public: //EffectImpl static HRESULT Register(_In_ ID2D1Factory1 *pFactory); static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect); IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface); IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); }; IFACEMETHODIMP_(ULONG) Release(void); IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph); IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type); IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph); //DrawTransform IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw); IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const; IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque); IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const; IFACEMETHODIMP_(UINT32) GetInputCount(void) const; //Added HRESULT SetTint(UINT32 Clr); UINT32 GetTint(void) const; private: MyEffect(void); ~MyEffect(void); // Data DWORD Signature; LONG ctReference; ID2D1EffectContext *pCtx; ID2D1DrawInfo *pDraw; UINT ctInput; D2D1_RECT_L rIn[MAX_INPUT]; struct ShaderConstant_s { float tint[4]; } Constants; }; class PxlShader { public: static PxlShader *Ptr(void *pObj); static PxlShader *Ptr(HWND hWnd); static int Create(HWND &hWnd); private: PxlShader(void); ~PxlShader(void); int Create2(void); static INT_PTR CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm); LRESULT WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm); int MsgCreate(HWND hWnd); int MsgDestroy(void); int MsgClose(void); int MsgTimer(void); int MsgMoved(void); int MsgPaint(void); int DrawCreate(void); int DrawCreateDX(void); int DrawCreateSwapChain(void); int DrawCreateD2Factory(void); int CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase); int CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite); int CreateEffect(void); int DrawUpdate(void); int DrawShow(void); void ReleaseEverything(void); //Data DWORD Signature; HWND hWnd; RECT rWnd; // Window client area POINT2D ptBall; // Bouncing ball position POINT2D BallVector; // Bouncing ball vector D3D_FEATURE_LEVEL DxFeatures; // Supported feature set IDXGIFactory2 *pDXGIFactory; IDXGISwapChain1 *pSwapChain; IDXGISurface1 *pDXGISurface; IDXGIDevice *pDXGIDevice; ID2D1Factory1 *pD2Factory; ID2D1Device *pD2Device; ID2D1DeviceContext *pdcDraw; ID2D1Bitmap1 *pbmImg; ID2D1Bitmap1 *pbmSrc1; ID2D1Bitmap1 *pbmSrc2; ID2D1Effect *pEffect; }; /*************************************************************************/ /** Window entry point **/ /*************************************************************************/ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pArgs, int nShow) { int Err= ERR_OK; HWND hWnd= 0; ghInst= hInst; MemCreate(); TmpBufCreate(16*1024*1024); if(IsErr(Err= PxlShader::Create(hWnd))) { Err= Error(Err,"WinMain: Unable to create the main window."); } else { while(hWnd && IsWindow(hWnd)) { MSG Msg; GetMessage(&Msg,hWnd,0,0); TranslateMessage(&Msg); DispatchMessage(&Msg); } } TmpBufDestroy(); MemDestroy(); if(IsErr(MemReport())) MessageBox(0,L"PxlShader: Memory error.",L"PxlShader",MB_OK|MB_SETFOREGROUND); return(Err); } void ConsolePrint(DWORD Type, const WCHAR *Text) { TXT Out(0,0,"%s\r\n",Text); OutputDebugString(Out); } /*************************************************************************/ /** PxlShader class **/ /*************************************************************************/ PxlShader::PxlShader(void) { Signature= SIGNATURE_PXLSHADER; ptBall= { 10,20 }; BallVector= { 1,1 }; } PxlShader::~PxlShader(void) { Signature|= SIGNATURE_INVALID; ReleaseEverything(); } PxlShader *PxlShader::Ptr(void *pObj) { PxlShader *pPxl= (PxlShader*)pObj; if(!pObj || IsBadPtr(pObj,sizeof(*pPxl),BADPTR_RW) || pPxl->Signature!=SIGNATURE_PXLSHADER) pPxl= 0; return(pPxl); } PxlShader *PxlShader::Ptr(HWND hWnd) { if(!hWnd || !IsWindow(hWnd)) return(0); return(Ptr((void*)GetWindowLongPtr(hWnd,GWLP_USERDATA))); } int PxlShader::Create(HWND &hWnd) { int Err= ERR_OK; PxlShader *pPxl= new PxlShader; if(!pPxl) { Err= Error(ERR_NO_MEM,"PxlShader:Create: NoMem"); } else if(IsErr(Err= pPxl->Create2())) { delete pPxl; } else { hWnd= pPxl->hWnd; } return(Err); } int PxlShader::Create2(void) { int Err= ERR_OK; ATOM hWndClass; WNDCLASS WndClass; RECT R= { 100,100,500,300 }; Zero(WndClass); WndClass.style= CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW; WndClass.lpfnWndProc= WndProc; WndClass.hInstance= ghInst; WndClass.lpszClassName= ClassName; DWORD style= WS_OVERLAPPEDWINDOW|WS_VISIBLE; if(!(hWndClass= RegisterClass(&WndClass))) { Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to register the main window class."); } else if(!(hWnd= CreateWindow(ClassName,L"PxlShader",style,R.left,R.top,RWID(R),RHGT(R),0,0,ghInst,(LPVOID)this))) { Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to create the main window."); } return(Err); } /*************************************************************************/ /** Window message handler **/ /*************************************************************************/ INT_PTR CALLBACK PxlShader::WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) { INT_PTR Result= 0; PxlShader *pPxl= 0; if(Msg==WM_CREATE) { CREATESTRUCT *pCreate= (CREATESTRUCT*)lParm; pPxl= Ptr(pCreate->lpCreateParams); } else { pPxl= Ptr(hWnd); } if(!pPxl) { Result= DefWindowProc(hWnd,Msg,wParm,lParm); } else { Result= pPxl->WndProc2(hWnd,Msg,wParm,lParm); } return(Result); } LRESULT PxlShader::WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) { LRESULT Result= 0; switch(Msg) { case WM_CREATE: Result= MsgCreate(hWnd); break; case WM_DESTROY: Result= MsgDestroy(); break; case WM_CLOSE: Result= MsgClose(); break; case WM_TIMER: Result= MsgTimer(); break; case WM_WINDOWPOSCHANGED: Result= MsgMoved(); break; case WM_PAINT: Result= MsgPaint(); break; default: Result= DefWindowProc(hWnd,Msg,wParm,lParm); break; } return(Result); } int PxlShader::MsgCreate(HWND _hWnd) { hWnd= _hWnd; SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)this); SetTimer(hWnd,1,30,0); return(1); } int PxlShader::MsgDestroy(void) { SetWindowLongPtr(hWnd,GWLP_USERDATA,0); delete this; return(1); } int PxlShader::MsgClose(void) { DestroyWindow(hWnd); return(1); } int PxlShader::MsgTimer(void) { ptBall.x+= BallVector.x; if(ptBall.x < rWnd.left || ptBall.x >= rWnd.right) { BallVector.x= -BallVector.x; ptBall.x+= BallVector.x*2; } ptBall.y+= BallVector.y; if(ptBall.y < rWnd.top || ptBall.y >= rWnd.bottom) { BallVector.y= -BallVector.y; ptBall.y+= BallVector.y*2; } if(pEffect) { UINT32 Tint= ((UINT32)rand()<<16)|rand(); pEffect->SetValueByName(L"Tint",Tint); } InvalidateRect(hWnd,0,0); return(1); } int PxlShader::MsgMoved(void) { RECT rNew; GetClientRect(hWnd,&rNew); if(RWID(rNew)!=RWID(rWnd) || RHGT(rNew)!=RHGT(rWnd)) { rWnd= rNew; ReleaseEverything(); } return(1); } int PxlShader::MsgPaint(void) { int Err= ERR_OK; PAINTSTRUCT Pnt; GetClientRect(hWnd,&rWnd); if(BeginPaint(hWnd,&Pnt)) { if(IsErr(Err= DrawCreate())) { Err= Warn(Err,"PxlShader:MsgPaint: DrawCreate() failed."); } else if(IsErr(Err= DrawUpdate())) { Err= Warn(Err,"PxlShader:MsgPaint: DrawUdpate() failed."); } else if(IsErr(Err= DrawShow())) { Err= Warn(Err,"PxlShader:MsgPaint: DrawPaint() failed."); } if(IsErr(Err)) { // Fall back to GDI paint. HBRUSH hbrFill= CreateSolidBrush(RGB(20,30,40)); FillRect(Pnt.hdc,&Pnt.rcPaint,hbrFill); DeleteObject(hbrFill); } EndPaint(hWnd,&Pnt); } ValidateRect(hWnd,0); return(1); } /*************************************************************************/ /** DirectX **/ /*************************************************************************/ int PxlShader::DrawCreate(void) { int Err= ERR_OK; HRESULT WinErr; D2D1_SIZE_U szWnd= { (UINT32)RWID(rWnd), (UINT32)RHGT(rWnd) }; D2D1_DEVICE_CONTEXT_OPTIONS DCOptions= D2D1_DEVICE_CONTEXT_OPTIONS_NONE; if(!pDXGIDevice && IsErr(DrawCreateDX())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create DXGI device."); } else if(!pSwapChain && IsErr(Err= DrawCreateSwapChain())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create SwapChain."); } else if(!pDXGISurface && !SUCCEEDED(WinErr= pSwapChain->GetBuffer(0,IID_PPV_ARGS(&pDXGISurface)))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to retrieve DXGI surface. [%X]",WinErr); } else if(!pD2Factory && IsErr(Err= DrawCreateD2Factory())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D factory."); } else if(!pD2Device && !SUCCEEDED(WinErr= pD2Factory->CreateDevice(pDXGIDevice,&pD2Device))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D device."); } else if(!pdcDraw && !SUCCEEDED(WinErr= pD2Device->CreateDeviceContext(DCOptions,&pdcDraw))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Draw context."); } else if(!pbmImg && IsErr(Err= CreateBitmapBase(pdcDraw,szWnd,pbmImg))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create base bitmap."); } else if(!pEffect && IsErr(Err= CreateEffect())) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create MyEffect."); } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap."); } return(Err); } int PxlShader::DrawCreateDX(void) { int Err= ERR_OK; HRESULT WinErr; UINT Flags= D3D11_CREATE_DEVICE_BGRA_SUPPORT; static const D3D_FEATURE_LEVEL Levels[]= { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2, D3D_FEATURE_LEVEL_9_1 }; D3D_DRIVER_TYPE Type= D3D_DRIVER_TYPE_HARDWARE; UINT ctLevels= ARRAYSIZE(Levels); UINT Version= D3D11_SDK_VERSION; ID3D11Device *pD3D11Device= 0; ID3D11DeviceContext *pD3D11DC= 0; IDXGIAdapter *pDXGIAdapter= 0; if(!SUCCEEDED(WinErr= D3D11CreateDevice(0,Type,0,Flags,Levels,ctLevels,Version,&pD3D11Device,&DxFeatures,&pD3D11DC))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: D3D11CreateDevice() failed."); } else if(!SUCCEEDED(WinErr= pD3D11Device->QueryInterface(&pDXGIDevice))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI device. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pDXGIDevice->GetAdapter(&pDXGIAdapter))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI adapter. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pDXGIAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory)))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI factory. [%X]",WinErr); } SafeRelease(pDXGIAdapter); SafeRelease(pD3D11Device); SafeRelease(pD3D11DC); return(Err); } int PxlShader::DrawCreateSwapChain(void) { int Err= ERR_OK; HRESULT WinErr; DXGI_SWAP_CHAIN_DESC1 SwapDesc; Zero(SwapDesc); SwapDesc.Format= DXGI_FORMAT_B8G8R8A8_UNORM; SwapDesc.SampleDesc.Count= 1; SwapDesc.BufferUsage= DXGI_USAGE_RENDER_TARGET_OUTPUT; SwapDesc.BufferCount= 2; SwapDesc.Scaling= DXGI_SCALING_STRETCH; SwapDesc.SwapEffect= DXGI_SWAP_EFFECT_DISCARD; if(!SUCCEEDED(WinErr= pDXGIFactory->CreateSwapChainForHwnd(pDXGIDevice,hWnd,&SwapDesc,0,0,&pSwapChain))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateSwapChain: Unable to create SwapChain. [%X]",WinErr); } return(Err); } int PxlShader::DrawCreateD2Factory(void) { int Err= ERR_OK; HRESULT WinErr; REFIID guid= __uuidof(ID2D1Factory1); D2D1_FACTORY_OPTIONS options; options.debugLevel= D2D1_DEBUG_LEVEL_INFORMATION; // DEBUG_LEVEL will trigger exceptions if EndDraw() fails or the factory is released with // outstanding (unreleased) objects. if(!SUCCEEDED(WinErr= D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,guid,&options,(void**)&pD2Factory))) { Err= Error(ERR_DIRECTX,"PxlShader:DrawCreateD2Factory: Unable to create D2D factory. [%X]",WinErr); } return(Err); } // Create a targetable bitmap from a DXGI surface. // This serves as the final rendering destination bitmap. int PxlShader::CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase) { int Err= ERR_OK; HRESULT WinErr; IDXGISurface *pSurface= 0; D2D1_BITMAP_PROPERTIES1 bmProp; Zero(bmProp); bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET|D2D1_BITMAP_OPTIONS_CANNOT_DRAW; bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_IGNORE); pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY); if(!SUCCEEDED(WinErr= pdcDst->CreateBitmapFromDxgiSurface(pDXGISurface,bmProp,&pbmBase))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapBase: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height); } else { pdcDst->SetTarget(pbmBase); } return(Err); } // Create a targetable bitmap that can be used for compositing. int PxlShader::CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite) { int Err= ERR_OK; HRESULT WinErr; D2D1_BITMAP_PROPERTIES1 bmProp; Zero(bmProp); bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET; bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_PREMULTIPLIED); pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY); if(!SUCCEEDED(WinErr= pdcDst->CreateBitmap(szBitmap,0,0,bmProp,&pbmComposite))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapComposite: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height); } else { pdcDst->SetTarget(pbmComposite); } return(Err); } int PxlShader::CreateEffect(void) { int Err= ERR_OK; HRESULT WinErr; if(!SUCCEEDED(WinErr= MyEffect::Register(pD2Factory))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to register MyEffect. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pdcDraw->CreateEffect(CLSID_MyEffect,&pEffect))) { Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to create MyEffect. [%X]",WinErr); } else { Print(PRINT_INFO,"PxlShader:CreateEffect: OK"); } return(Err); } void PxlShader::ReleaseEverything(void) { SafeRelease(pEffect); SafeRelease(pbmSrc2); SafeRelease(pbmSrc1); SafeRelease(pbmImg); SafeRelease(pdcDraw); SafeRelease(pD2Device); SafeRelease(pD2Factory); SafeRelease(pDXGIDevice); SafeRelease(pDXGISurface); SafeRelease(pSwapChain); SafeRelease(pDXGIFactory); } /*************************************************************************/ /** Draw **/ /*************************************************************************/ int PxlShader::DrawUpdate(void) { int Err= ERR_OK; HRESULT WinErr; pdcDraw->BeginDraw(); pdcDraw->SetTransform(Matrix3x2F::Identity()); pdcDraw->SetTarget(pbmSrc1); pdcDraw->Clear(ColorF(ColorF::Black,0)); D2D1_RECT_F box= { 0,0,80,60 }; pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod))); pdcDraw->SetTarget(pbmSrc2); pdcDraw->Clear(ColorF(ColorF::Black,0)); D2D1_ELLIPSE dot= { {50,50}, 50,50 }; pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen))); pdcDraw->SetTarget(pbmImg); pdcDraw->Clear(ColorF(ColorF::Black,0)); pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y))); pEffect->SetInput(0,pbmSrc1); pEffect->SetInput(1,pbmSrc2); pdcDraw->DrawImage(pEffect); if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) { Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr); ReleaseEverything(); } return(Err); } int PxlShader::DrawShow(void) { int Err= ERR_OK; HRESULT WinErr; DXGI_PRESENT_PARAMETERS PresentParm; Zero(PresentParm); if(!SUCCEEDED(WinErr= pSwapChain->Present1(1,0,&PresentParm))) { Err= Warn(ERR_DIRECTX,"PxlShader:DrawShow: Present() failed. [%X]",WinErr); } return(Err); } /*************************************************************************/ /** MyEffect **/ /*************************************************************************/ MyEffect::MyEffect(void) { Signature= SIGNATURE_MYEFFECT; ctReference= 1; ctInput= 0; Zero(Constants); Constants.tint[2]= 0.50f; } MyEffect::~MyEffect(void) { Signature|= SIGNATURE_INVALID; } ULONG MyEffect::Release(void) { if(--ctReference > 0) return(ctReference); delete this; return(0); } HRESULT MyEffect::QueryInterface(REFIID riid, void **ppInterface) { HRESULT WinErr= S_OK; void *pInterface= 0; if(riid==__uuidof(ID2D1EffectImpl)) { pInterface= reinterpret_cast<ID2D1EffectImpl*>(this); } else if(riid==__uuidof(ID2D1DrawTransform)) { pInterface= static_cast<ID2D1DrawTransform*>(this); } else if(riid==__uuidof(ID2D1Transform)) { pInterface= static_cast<ID2D1Transform*>(this); } else if(riid==__uuidof(ID2D1TransformNode)) { pInterface= static_cast<ID2D1TransformNode*>(this); } else if(riid==__uuidof(ID2D1ComputeTransform)) { Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a compute transform."); WinErr= E_NOINTERFACE; } else if(riid==__uuidof(ID2D1SourceTransform)) { Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a source transform."); WinErr= E_NOINTERFACE; } else if(riid==__uuidof(IUnknown)) { pInterface= this; } else { WinErr= E_NOINTERFACE; } if(ppInterface) { *ppInterface= pInterface; if(pInterface) AddRef(); } return(WinErr); } HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) { HRESULT WinErr= S_OK; static const PCWSTR pszXml = L"<?xml version='1.0'?>\r\n" L"<Effect>\r\n" L" <!-- System Properties -->\r\n" L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n" L" <Property name='Author' type='string' value='nlited systems'/>\r\n" L" <Property name='Category' type='string' value='Experimental'/>\r\n" L" <Property name='Description' type='string' value='My first effect.'/>\r\n" L" <Inputs minimum='0' maximum='2'>\r\n" // Source must be specified. L" <Input name='Source1'/>\r\n" L" <Input name='Source2'/>\r\n" L" </Inputs>\r\n" L" <!-- Custom Properties go here. -->\r\n" L" <Property name='Tint' type='uint32'>\r\n" L" <Property name='DisplayName' type='string' value='Tint'/>\r\n" L" <Property name='Default' type='uint32' value='0'/>\r\n" L" </Property>\r\n" L"</Effect>\r\n" ; static const D2D1_PROPERTY_BINDING Bindings[]= { D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint) }; if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) { Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr); } return(WinErr); } HRESULT __stdcall MyEffect::CreateMyEffect(IUnknown **ppEffect) { HRESULT WinErr= S_OK; *ppEffect= static_cast<ID2D1EffectImpl*>(new MyEffect); if(!*ppEffect) { WinErr= E_OUTOFMEMORY; } return(WinErr); } HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) { HRESULT WinErr= S_OK; ID3DBlob *pCode= 0; ID3DBlob *pError= 0; pCtx= _pCtx; if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"S:\\Src\\HQ\\Dev\\SB\\Chip\\Bugs\\BugsV1\\Out\\Winx64Debug\\FirstShader.cso",&pCode))) { Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr); } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) { Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr); } else { ctInput= 2; Print(PRINT_INFO,"MyEffect:Initialize: OK."); } SafeRelease(pCode); SafeRelease(pError); return(WinErr); } // This is a single-transform, single-node graph, SetGraph() should never be called. HRESULT MyEffect::SetGraph(ID2D1TransformGraph *pGraph) { Warn(ERR_DIRECTX,"MyEffect:SetGraph: Should not be called."); return(E_NOTIMPL); } HRESULT MyEffect::SetTint(UINT32 Clr) { Constants.tint[0]= (float)((Clr>>16) & 0xFF)/255.0f; Constants.tint[1]= (float)((Clr>> 8) & 0xFF)/255.0f; Constants.tint[2]= (float)((Clr ) & 0xFF)/255.0f; Constants.tint[3]= (float)((Clr>>24) & 0xFF)/255.0f; return(S_OK); } UINT32 MyEffect::GetTint(void) const { UINT32 Clr= 0; Clr|= ((UINT32)(Constants.tint[0]*255.0f) & 0xFF)<<16; Clr|= ((UINT32)(Constants.tint[1]*255.0f) & 0xFF)<< 8; Clr|= ((UINT32)(Constants.tint[2]*255.0f) & 0xFF); Clr|= ((UINT32)(Constants.tint[3]*255.0f) & 0xFF)<<24; return(Clr); } HRESULT MyEffect::PrepareForRender(D2D1_CHANGE_TYPE Type) { HRESULT WinErr= S_OK; pDraw->SetPixelShaderConstantBuffer((BYTE*)&Constants,sizeof(Constants)); return(WinErr); } // ID2D1DrawTransform HRESULT MyEffect::SetDrawInfo(ID2D1DrawInfo *_pDraw) { HRESULT WinErr= S_OK; pDraw= _pDraw; if(!SUCCEEDED(WinErr= pDraw->SetPixelShader(GUID_MyPixelShader))) { Warn(ERR_DIRECTX,"MyEffect:SetDrawInfo: SetPixelShader() failed. [%X]",WinErr); } return(WinErr); } HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const { HRESULT WinErr= S_OK; //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn); if(ctIn==0) { Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?"); } else if(ctIn>MAX_INPUT) { Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn); WinErr= E_INVALIDARG; } else if(ctIn>0) { prIn[0]= *prOut; for(UINT n1=1;n1<ctIn;n1++) { prIn[n1]= *prOut; } } return(WinErr); } IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) { HRESULT WinErr= S_OK; //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn); if(ctIn==0) { Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?"); } else if(ctIn>MAX_INPUT) { Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn); WinErr= E_INVALIDARG; } else if(ctIn>0) { *prOut= rIn[0]= prIn[0]; for(UINT n1=1;n1<ctIn;n1++) { rIn[n1]= prIn[n1]; } Zero(*prOutOpaque); } return(WinErr); } IFACEMETHODIMP MyEffect::MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOutInvalid) const { HRESULT WinErr= S_OK; Print(PRINT_DEBUG,"MyEffect:MapInvalidRect:"); // Set entire output to invalid *prOutInvalid= rIn[0]; return(WinErr); } IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const { return(MAX_INPUT); } //EOF: PXLSHADER.CPP

Moderator: close comments Comments are closed.

Comments are moderated. Anonymous comments are not visible to others until moderated. Comments are owned by the author but may be removed or reused (but not modified) by this site at any time without notice.

HTML
  1. Moderator: [] approve delete HTML



WebV7 (C)2018 nlited | Rendered by tikope in 49.685ms | 18.227.209.101