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:
What should GetInputCount() return? The maximum number of inputs
supported or the number of inputs currently defined?
UPDATE: The number of inputs expected . This is a hard-coded number.
How do I handle the Map...Rects() functions when there are multiple
inputs?
UPDATE: Copy the rectangle to/from all input rectangles.
Do I need to define a separate instance of ID2D1Transform for each
input?
UPDATE: No: There is one transform with multiple inputs. I can still
use a single class that is an amalgam of ID2D1EffectImpl and ID2D1DrawTransform.
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!
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.
TEXT MyEffect declaration :
1 #define MAX_INPUT 2
2
3 class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform {
4 public:
5 //EffectImpl
6 static HRESULT Register(_In_ ID2D1Factory1 *pFactory);
7 static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect);
8 IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface);
9 IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); };
10 IFACEMETHODIMP_(ULONG) Release(void);
11 IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph);
12 IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type);
13 IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph);
14 //DrawTransform
15 IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw);
16 IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const;
17 IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque);
18 IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const;
19 IFACEMETHODIMP_(UINT32) GetInputCount(void) const;
20 //Added
21 HRESULT SetTint(UINT32 Clr);
22 UINT32 GetTint(void) const;
23 private:
24 MyEffect(void);
25 ~MyEffect(void);
26 // Data
27 DWORD Signature;
28 LONG ctReference;
29 ID2D1EffectContext *pCtx;
30 ID2D1DrawInfo *pDraw;
31 UINT ctInput;
32 D2D1_RECT_L rIn[MAX_INPUT];
33 struct ShaderConstant_s {
34 float tint[4];
35 } Constants;
36 };
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.
TEXT MyEffect::Register() :
1 HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) {
2 HRESULT WinErr= S_OK;
3 static const PCWSTR pszXml =
4 L"<?xml version='1.0'?>\r\n"
5 L"<Effect>\r\n"
6 L" <!-- System Properties -->\r\n"
7 L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n"
8 L" <Property name='Author' type='string' value='nlited systems'/>\r\n"
9 L" <Property name='Category' type='string' value='Experimental'/>\r\n"
10 L" <Property name='Description' type='string' value='My first effect.'/>\r\n"
11 L" <Inputs minimum='0' maximum='2' >\r\n"
12 // Source must be specified.
13 L" <Input name='Source1'/>\r\n"
14 L" <Input name='Source2'/>\r\n"
15 L" </Inputs>\r\n"
16 L" <!-- Custom Properties go here. -->\r\n"
17 L" <Property name='Tint' type='uint32'>\r\n"
18 L" <Property name='DisplayName' type='string' value='Tint'/>\r\n"
19 L" <Property name='Default' type='uint32' value='0'/>\r\n"
20 L" </Property>\r\n"
21 L"</Effect>\r\n"
22 ;
23 static const D2D1_PROPERTY_BINDING Bindings[]= {
24 D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint)
25 };
26 if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) {
27 Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr);
28 }
29 return(WinErr);
30 }
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.
TEXT MyEffect::Initialize() :
1 HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) {
2 HRESULT WinErr= S_OK;
3 ID3DBlob *pCode= 0;
4 ID3DBlob *pError= 0;
5 pCtx= _pCtx;
6 if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"S:\\Src\\HQ\\Dev\\SB\\Chip\\Bugs\\BugsV1\\Out\\Winx64Debug\\FirstShader.cso",&pCode))) {
7 Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr);
8 } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) {
9 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr);
10 } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) {
11 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr);
12 } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) {
13 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr);
14 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) {
15 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr);
16 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) {
17 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr);
18 } else {
19 ctInput= 2;
20 Print(PRINT_INFO,"MyEffect:Initialize: OK.");
21 }
22 SafeRelease(pCode);
23 SafeRelease(pError);
24 return(WinErr);
25 }
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.
TEXT MyEffect::MapRects :
1 HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const {
2 HRESULT WinErr= S_OK;
3 //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn);
4 if(ctIn==0) {
5 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?");
6 } else if(ctIn>MAX_INPUT) {
7 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn);
8 WinErr= E_INVALIDARG;
9 } else if(ctIn>0) {
10 prIn[0]= *prOut;
11 for(UINT n1=1;n1<ctIn;n1++) {
12 prIn[n1]= *prOut;
13 }
14 }
15 return(WinErr);
16 }
17
18 IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) {
19 HRESULT WinErr= S_OK;
20 //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn);
21 if(ctIn==0) {
22 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?");
23 } else if(ctIn>MAX_INPUT) {
24 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn);
25 WinErr= E_INVALIDARG;
26 } else if(ctIn>0) {
27 *prOut= rIn[0]= prIn[0];
28 for(UINT n1=1;n1<ctIn;n1++) {
29 rIn[n1]= prIn[n1];
30 }
31 Zero(*prOutOpaque);
32 }
33 return(WinErr);
34 }
MapInvalidRect() remains the same.
GetInputCount() needs to return the expected number of inputs,
not the number currently connected.
TEXT MyEffect::GetInputCount() :
1 IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const {
2 return(MAX_INPUT);
3 }
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.
TEXT PxlShader declaration :
1 class PxlShader {
2 ...
3 private:
4 ...
5 ID2D1Bitmap1 *pbmSrc1;
6 ID2D1Bitmap1 *pbmSrc2;
7 };
8
9 int PxlShader::DrawCreate(void) {
10 ...
11 } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) {
12 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap.");
13 } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) {
14 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap.");
15 }
16 return(Err);
17 }
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.
TEXT PxlShader::DrawUpdate() :
1 int PxlShader::DrawUpdate(void) {
2 int Err= ERR_OK;
3 HRESULT WinErr;
4 pdcDraw->BeginDraw();
5 pdcDraw->SetTransform(Matrix3x2F::Identity());
6 pdcDraw->SetTarget(pbmSrc1);
7 pdcDraw->Clear(ColorF(ColorF::Black,0));
8 D2D1_RECT_F box= { 0,0,80,60 };
9 pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod)));
10 pdcDraw->SetTarget(pbmSrc2);
11 pdcDraw->Clear(ColorF(ColorF::Black,0));
12 D2D1_ELLIPSE dot= { {50,50}, 50,50 };
13 pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen)));
14 pdcDraw->SetTarget(pbmImg);
15 pdcDraw->Clear(ColorF(ColorF::Black,0));
16 pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y)));
17 pEffect->SetInput(0,pbmSrc1);
18 pEffect->SetInput(1,pbmSrc2);
19 pdcDraw->DrawImage(pEffect);
20 if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) {
21 Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr);
22 ReleaseEverything();
23 }
24 return(Err);
25 }
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.
TEXT FirstShader.hlsl :
1 #define D2D_INPUT_COUNT 2
2 #include "d2d1effecthelpers.hlsli"
3
4 cbuffer constants: register(b0) {
5 float4 tint:COLOR;
6 };
7
8 D2D_PS_ENTRY(main) {
9 float4 color;
10 float4 color0= D2DGetInput(0);
11 float4 color1= D2DGetInput(1);
12 color= (color0+color1)/2;
13 return color;
14 }
15
16 //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.
The non-overlap regions are dark because I am averaging in the
black pixels. I can fix that...
TEXT Shader2 :
1 #define D2D_INPUT_COUNT 2
2 #include "d2d1effecthelpers.hlsli"
3
4 cbuffer constants: register(b0) {
5 float4 tint:COLOR;
6 };
7
8 D2D_PS_ENTRY(main) {
9 float4 color;
10 float4 color0= D2DGetInput(0);
11 float4 color1= D2DGetInput(1);
12 if(color0.a==0) {
13 color= color1;
14 } else if(color1.a==0) {
15 color= color0;
16 } else {
17 color= (color0+color1)/2;
18 }
19 return color;
20 }
21
22 //EOF: FIRSTSHADER.HLSL
Success! I now know how to merge two source bitmaps into a
single output image.
The complete PxlShader app:
TEXT PxlShader.cpp :
1 /*************************************************************************/
2 /** PxlShader.cpp: Minimal code to run a pixel shader. **/
3 /** (C)2022 nlited systems, cmd **/
4 /*************************************************************************/
5 #include <Windows.h>
6 #include <d3d11_1.h>
7 #include <d2d1.h>
8 #include <d2d1_1.h>
9 #include <d2d1helper.h>
10 #include <d2d1effectauthor.h>
11 #include <d2d1effecthelpers.h>
12 #include <d3dcompiler.h>
13 #include "Handles.h"
14 #include "ChipLib.h"
15
16 #pragma comment(lib,"D3D11.lib")
17 #pragma comment(lib,"D2D1.lib")
18 #pragma comment(lib,"DXGI.lib")
19 #pragma comment(lib,"d3dcompiler.lib")
20
21 #pragma message(__FILE__": Optimizer disabled.")
22 #pragma optimize("",off)
23
24 #define SIGNATURE_PXLSHADER 0xCD190001
25 #define SIGNATURE_MYEFFECT 0xCD190002
26 #define SIGNATURE_MYTRANSFORM 0xCD190003
27
28 using namespace D2D1;
29 typedef D2D1_POINT_2F POINT2D;
30
31 HINSTANCE ghInst;
32 DWORD DbgFilter;
33 static const WCHAR ClassName[]= { L"PxlShader" };
34
35 // {D8255497-025E-4D3F-A4DF-5C25306F67AC}
36 static const GUID CLSID_MyEffect = { 0xd8255497, 0x25e, 0x4d3f, { 0xa4, 0xdf, 0x5c, 0x25, 0x30, 0x6f, 0x67, 0xac } };
37
38 // {2BCB702A-4F42-44D0-B8ED-4E9F9FC7A905}
39 static const GUID GUID_MyPixelShader = { 0x2bcb702a, 0x4f42, 0x44d0, { 0xb8, 0xed, 0x4e, 0x9f, 0x9f, 0xc7, 0xa9, 0x5 } };
40
41 #define SafeRelease(pInterface) { if(pInterface && pInterface->Release()==0) pInterface= 0; }
42
43 //Auto-destruct solid brush.
44 class D2Brush {
45 public:
46 D2Brush(ID2D1RenderTarget *pRT, const D2D1_COLOR_F &clr) {
47 pRT->CreateSolidColorBrush(clr,&pbrBrush);
48 };
49 ~D2Brush(void) {
50 pbrBrush->Release();
51 }
52 operator ID2D1Brush *() { return(static_cast<ID2D1Brush*>(pbrBrush)); };
53 // This lets me use the object as the parameter to the various RenderTarget functions.
54 ID2D1SolidColorBrush *pbrBrush;
55 };
56
57 #define MAX_INPUT 2
58
59 class MyEffect: public ID2D1EffectImpl, public ID2D1DrawTransform {
60 public:
61 //EffectImpl
62 static HRESULT Register(_In_ ID2D1Factory1 *pFactory);
63 static HRESULT __stdcall CreateMyEffect(_Outptr_ IUnknown **ppEffect);
64 IFACEMETHODIMP QueryInterface(REFIID riid, void **ppInterface);
65 IFACEMETHODIMP_(ULONG) AddRef(void) { return(++ctReference); };
66 IFACEMETHODIMP_(ULONG) Release(void);
67 IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext *pCtx, _In_ ID2D1TransformGraph *pGraph);
68 IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE Type);
69 IFACEMETHODIMP SetGraph(ID2D1TransformGraph *pGraph);
70 //DrawTransform
71 IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo *pDraw);
72 IFACEMETHODIMP MapOutputRectToInputRects(const D2D1_RECT_L *prOut, D2D1_RECT_L *prIn, UINT32 ctIn) const;
73 IFACEMETHODIMP MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque);
74 IFACEMETHODIMP MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOut) const;
75 IFACEMETHODIMP_(UINT32) GetInputCount(void) const;
76 //Added
77 HRESULT SetTint(UINT32 Clr);
78 UINT32 GetTint(void) const;
79 private:
80 MyEffect(void);
81 ~MyEffect(void);
82 // Data
83 DWORD Signature;
84 LONG ctReference;
85 ID2D1EffectContext *pCtx;
86 ID2D1DrawInfo *pDraw;
87 UINT ctInput;
88 D2D1_RECT_L rIn[MAX_INPUT];
89 struct ShaderConstant_s {
90 float tint[4];
91 } Constants;
92 };
93
94 class PxlShader {
95 public:
96 static PxlShader *Ptr(void *pObj);
97 static PxlShader *Ptr(HWND hWnd);
98 static int Create(HWND &hWnd);
99 private:
100 PxlShader(void);
101 ~PxlShader(void);
102 int Create2(void);
103 static INT_PTR CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm);
104 LRESULT WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm);
105 int MsgCreate(HWND hWnd);
106 int MsgDestroy(void);
107 int MsgClose(void);
108 int MsgTimer(void);
109 int MsgMoved(void);
110 int MsgPaint(void);
111 int DrawCreate(void);
112 int DrawCreateDX(void);
113 int DrawCreateSwapChain(void);
114 int DrawCreateD2Factory(void);
115 int CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase);
116 int CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite);
117 int CreateEffect(void);
118 int DrawUpdate(void);
119 int DrawShow(void);
120 void ReleaseEverything(void);
121 //Data
122 DWORD Signature;
123 HWND hWnd;
124 RECT rWnd; // Window client area
125 POINT2D ptBall; // Bouncing ball position
126 POINT2D BallVector; // Bouncing ball vector
127 D3D_FEATURE_LEVEL DxFeatures; // Supported feature set
128 IDXGIFactory2 *pDXGIFactory;
129 IDXGISwapChain1 *pSwapChain;
130 IDXGISurface1 *pDXGISurface;
131 IDXGIDevice *pDXGIDevice;
132 ID2D1Factory1 *pD2Factory;
133 ID2D1Device *pD2Device;
134 ID2D1DeviceContext *pdcDraw;
135 ID2D1Bitmap1 *pbmImg;
136 ID2D1Bitmap1 *pbmSrc1;
137 ID2D1Bitmap1 *pbmSrc2;
138 ID2D1Effect *pEffect;
139 };
140
141 /*************************************************************************/
142 /** Window entry point **/
143 /*************************************************************************/
144 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR pArgs, int nShow) {
145 int Err= ERR_OK;
146 HWND hWnd= 0;
147 ghInst= hInst;
148 MemCreate();
149 TmpBufCreate(16*1024*1024);
150 if(IsErr(Err= PxlShader::Create(hWnd))) {
151 Err= Error(Err,"WinMain: Unable to create the main window.");
152 } else {
153 while(hWnd && IsWindow(hWnd)) {
154 MSG Msg;
155 GetMessage(&Msg,hWnd,0,0);
156 TranslateMessage(&Msg);
157 DispatchMessage(&Msg);
158 }
159 }
160 TmpBufDestroy();
161 MemDestroy();
162 if(IsErr(MemReport()))
163 MessageBox(0,L"PxlShader: Memory error.",L"PxlShader",MB_OK|MB_SETFOREGROUND);
164 return(Err);
165 }
166
167 void ConsolePrint(DWORD Type, const WCHAR *Text) {
168 TXT Out(0,0,"%s\r\n",Text);
169 OutputDebugString(Out);
170 }
171
172 /*************************************************************************/
173 /** PxlShader class **/
174 /*************************************************************************/
175 PxlShader::PxlShader(void) {
176 Signature= SIGNATURE_PXLSHADER;
177 ptBall= { 10,20 };
178 BallVector= { 1,1 };
179 }
180
181 PxlShader::~PxlShader(void) {
182 Signature|= SIGNATURE_INVALID;
183 ReleaseEverything();
184 }
185
186 PxlShader *PxlShader::Ptr(void *pObj) {
187 PxlShader *pPxl= (PxlShader*)pObj;
188 if(!pObj || IsBadPtr(pObj,sizeof(*pPxl),BADPTR_RW) || pPxl->Signature!=SIGNATURE_PXLSHADER)
189 pPxl= 0;
190 return(pPxl);
191 }
192
193 PxlShader *PxlShader::Ptr(HWND hWnd) {
194 if(!hWnd || !IsWindow(hWnd))
195 return(0);
196 return(Ptr((void*)GetWindowLongPtr(hWnd,GWLP_USERDATA)));
197 }
198
199 int PxlShader::Create(HWND &hWnd) {
200 int Err= ERR_OK;
201 PxlShader *pPxl= new PxlShader;
202 if(!pPxl) {
203 Err= Error(ERR_NO_MEM,"PxlShader:Create: NoMem");
204 } else if(IsErr(Err= pPxl->Create2())) {
205 delete pPxl;
206 } else {
207 hWnd= pPxl->hWnd;
208 }
209 return(Err);
210 }
211
212 int PxlShader::Create2(void) {
213 int Err= ERR_OK;
214 ATOM hWndClass;
215 WNDCLASS WndClass;
216 RECT R= { 100,100,500,300 };
217 Zero(WndClass);
218 WndClass.style= CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
219 WndClass.lpfnWndProc= WndProc;
220 WndClass.hInstance= ghInst;
221 WndClass.lpszClassName= ClassName;
222 DWORD style= WS_OVERLAPPEDWINDOW|WS_VISIBLE;
223 if(!(hWndClass= RegisterClass(&WndClass))) {
224 Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to register the main window class.");
225 } else if(!(hWnd= CreateWindow(ClassName,L"PxlShader",style,R.left,R.top,RWID(R),RHGT(R),0,0,ghInst,(LPVOID)this))) {
226 Err= Error(ERR_SYSCREATE,"PxlShader:Create2: Unable to create the main window.");
227 }
228 return(Err);
229 }
230
231 /*************************************************************************/
232 /** Window message handler **/
233 /*************************************************************************/
234 INT_PTR CALLBACK PxlShader::WndProc(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) {
235 INT_PTR Result= 0;
236 PxlShader *pPxl= 0;
237 if(Msg==WM_CREATE) {
238 CREATESTRUCT *pCreate= (CREATESTRUCT*)lParm;
239 pPxl= Ptr(pCreate->lpCreateParams);
240 } else {
241 pPxl= Ptr(hWnd);
242 }
243 if(!pPxl) {
244 Result= DefWindowProc(hWnd,Msg,wParm,lParm);
245 } else {
246 Result= pPxl->WndProc2(hWnd,Msg,wParm,lParm);
247 }
248 return(Result);
249 }
250
251 LRESULT PxlShader::WndProc2(HWND hWnd, UINT Msg, WPARAM wParm, LPARAM lParm) {
252 LRESULT Result= 0;
253 switch(Msg) {
254 case WM_CREATE: Result= MsgCreate(hWnd); break;
255 case WM_DESTROY: Result= MsgDestroy(); break;
256 case WM_CLOSE: Result= MsgClose(); break;
257 case WM_TIMER: Result= MsgTimer(); break;
258 case WM_WINDOWPOSCHANGED: Result= MsgMoved(); break;
259 case WM_PAINT: Result= MsgPaint(); break;
260 default: Result= DefWindowProc(hWnd,Msg,wParm,lParm); break;
261 }
262 return(Result);
263 }
264
265 int PxlShader::MsgCreate(HWND _hWnd) {
266 hWnd= _hWnd;
267 SetWindowLongPtr(hWnd,GWLP_USERDATA,(LONG_PTR)this);
268 SetTimer(hWnd,1,30,0);
269 return(1);
270 }
271
272 int PxlShader::MsgDestroy(void) {
273 SetWindowLongPtr(hWnd,GWLP_USERDATA,0);
274 delete this;
275 return(1);
276 }
277
278 int PxlShader::MsgClose(void) {
279 DestroyWindow(hWnd);
280 return(1);
281 }
282
283 int PxlShader::MsgTimer(void) {
284 ptBall.x+= BallVector.x;
285 if(ptBall.x < rWnd.left || ptBall.x >= rWnd.right) {
286 BallVector.x= -BallVector.x;
287 ptBall.x+= BallVector.x*2;
288 }
289 ptBall.y+= BallVector.y;
290 if(ptBall.y < rWnd.top || ptBall.y >= rWnd.bottom) {
291 BallVector.y= -BallVector.y;
292 ptBall.y+= BallVector.y*2;
293 }
294 if(pEffect) {
295 UINT32 Tint= ((UINT32)rand()<<16)|rand();
296 pEffect->SetValueByName(L"Tint",Tint);
297 }
298 InvalidateRect(hWnd,0,0);
299 return(1);
300 }
301
302 int PxlShader::MsgMoved(void) {
303 RECT rNew;
304 GetClientRect(hWnd,&rNew);
305 if(RWID(rNew)!=RWID(rWnd) || RHGT(rNew)!=RHGT(rWnd)) {
306 rWnd= rNew;
307 ReleaseEverything();
308 }
309 return(1);
310 }
311
312 int PxlShader::MsgPaint(void) {
313 int Err= ERR_OK;
314 PAINTSTRUCT Pnt;
315 GetClientRect(hWnd,&rWnd);
316 if(BeginPaint(hWnd,&Pnt)) {
317 if(IsErr(Err= DrawCreate())) {
318 Err= Warn(Err,"PxlShader:MsgPaint: DrawCreate() failed.");
319 } else if(IsErr(Err= DrawUpdate())) {
320 Err= Warn(Err,"PxlShader:MsgPaint: DrawUdpate() failed.");
321 } else if(IsErr(Err= DrawShow())) {
322 Err= Warn(Err,"PxlShader:MsgPaint: DrawPaint() failed.");
323 }
324 if(IsErr(Err)) {
325 // Fall back to GDI paint.
326 HBRUSH hbrFill= CreateSolidBrush(RGB(20,30,40));
327 FillRect(Pnt.hdc,&Pnt.rcPaint,hbrFill);
328 DeleteObject(hbrFill);
329 }
330 EndPaint(hWnd,&Pnt);
331 }
332 ValidateRect(hWnd,0);
333 return(1);
334 }
335
336 /*************************************************************************/
337 /** DirectX **/
338 /*************************************************************************/
339 int PxlShader::DrawCreate(void) {
340 int Err= ERR_OK;
341 HRESULT WinErr;
342 D2D1_SIZE_U szWnd= { (UINT32)RWID(rWnd), (UINT32)RHGT(rWnd) };
343 D2D1_DEVICE_CONTEXT_OPTIONS DCOptions= D2D1_DEVICE_CONTEXT_OPTIONS_NONE;
344 if(!pDXGIDevice && IsErr(DrawCreateDX())) {
345 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create DXGI device.");
346 } else if(!pSwapChain && IsErr(Err= DrawCreateSwapChain())) {
347 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create SwapChain.");
348 } else if(!pDXGISurface && !SUCCEEDED(WinErr= pSwapChain->GetBuffer(0,IID_PPV_ARGS(&pDXGISurface)))) {
349 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to retrieve DXGI surface. [%X]",WinErr);
350 } else if(!pD2Factory && IsErr(Err= DrawCreateD2Factory())) {
351 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D factory.");
352 } else if(!pD2Device && !SUCCEEDED(WinErr= pD2Factory->CreateDevice(pDXGIDevice,&pD2Device))) {
353 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Direct2D device.");
354 } else if(!pdcDraw && !SUCCEEDED(WinErr= pD2Device->CreateDeviceContext(DCOptions,&pdcDraw))) {
355 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create Draw context.");
356 } else if(!pbmImg && IsErr(Err= CreateBitmapBase(pdcDraw,szWnd,pbmImg))) {
357 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create base bitmap.");
358 } else if(!pEffect && IsErr(Err= CreateEffect())) {
359 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create MyEffect.");
360 } else if(!pbmSrc1 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc1))) {
361 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap.");
362 } else if(!pbmSrc2 && IsErr(Err= CreateBitmapComposite(pdcDraw,SizeU(100,100),pbmSrc2))) {
363 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreate: Unable to create source bitmap.");
364 }
365 return(Err);
366 }
367
368 int PxlShader::DrawCreateDX(void) {
369 int Err= ERR_OK;
370 HRESULT WinErr;
371 UINT Flags= D3D11_CREATE_DEVICE_BGRA_SUPPORT;
372 static const D3D_FEATURE_LEVEL Levels[]= {
373 D3D_FEATURE_LEVEL_11_1,
374 D3D_FEATURE_LEVEL_11_0,
375 D3D_FEATURE_LEVEL_10_1,
376 D3D_FEATURE_LEVEL_10_0,
377 D3D_FEATURE_LEVEL_9_3,
378 D3D_FEATURE_LEVEL_9_2,
379 D3D_FEATURE_LEVEL_9_1
380 };
381 D3D_DRIVER_TYPE Type= D3D_DRIVER_TYPE_HARDWARE;
382 UINT ctLevels= ARRAYSIZE(Levels);
383 UINT Version= D3D11_SDK_VERSION;
384 ID3D11Device *pD3D11Device= 0;
385 ID3D11DeviceContext *pD3D11DC= 0;
386 IDXGIAdapter *pDXGIAdapter= 0;
387 if(!SUCCEEDED(WinErr= D3D11CreateDevice(0,Type,0,Flags,Levels,ctLevels,Version,&pD3D11Device,&DxFeatures,&pD3D11DC))) {
388 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: D3D11CreateDevice() failed.");
389 } else if(!SUCCEEDED(WinErr= pD3D11Device->QueryInterface(&pDXGIDevice))) {
390 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI device. [%X]",WinErr);
391 } else if(!SUCCEEDED(WinErr= pDXGIDevice->GetAdapter(&pDXGIAdapter))) {
392 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI adapter. [%X]",WinErr);
393 } else if(!SUCCEEDED(WinErr= pDXGIAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory)))) {
394 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateDX: Unable to retrieve DXGI factory. [%X]",WinErr);
395 }
396 SafeRelease(pDXGIAdapter);
397 SafeRelease(pD3D11Device);
398 SafeRelease(pD3D11DC);
399 return(Err);
400 }
401
402 int PxlShader::DrawCreateSwapChain(void) {
403 int Err= ERR_OK;
404 HRESULT WinErr;
405 DXGI_SWAP_CHAIN_DESC1 SwapDesc;
406 Zero(SwapDesc);
407 SwapDesc.Format= DXGI_FORMAT_B8G8R8A8_UNORM;
408 SwapDesc.SampleDesc.Count= 1;
409 SwapDesc.BufferUsage= DXGI_USAGE_RENDER_TARGET_OUTPUT;
410 SwapDesc.BufferCount= 2;
411 SwapDesc.Scaling= DXGI_SCALING_STRETCH;
412 SwapDesc.SwapEffect= DXGI_SWAP_EFFECT_DISCARD;
413 if(!SUCCEEDED(WinErr= pDXGIFactory->CreateSwapChainForHwnd(pDXGIDevice,hWnd,&SwapDesc,0,0,&pSwapChain))) {
414 Err= Warn(ERR_DIRECTX,"PxlShader:DrawCreateSwapChain: Unable to create SwapChain. [%X]",WinErr);
415 }
416 return(Err);
417 }
418
419 int PxlShader::DrawCreateD2Factory(void) {
420 int Err= ERR_OK;
421 HRESULT WinErr;
422 REFIID guid= __uuidof(ID2D1Factory1);
423 D2D1_FACTORY_OPTIONS options;
424 options.debugLevel= D2D1_DEBUG_LEVEL_INFORMATION;
425 // DEBUG_LEVEL will trigger exceptions if EndDraw() fails or the factory is released with
426 // outstanding (unreleased) objects.
427 if(!SUCCEEDED(WinErr= D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,guid,&options,(void**)&pD2Factory))) {
428 Err= Error(ERR_DIRECTX,"PxlShader:DrawCreateD2Factory: Unable to create D2D factory. [%X]",WinErr);
429 }
430 return(Err);
431 }
432
433 // Create a targetable bitmap from a DXGI surface.
434 // This serves as the final rendering destination bitmap.
435 int PxlShader::CreateBitmapBase(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmBase) {
436 int Err= ERR_OK;
437 HRESULT WinErr;
438 IDXGISurface *pSurface= 0;
439 D2D1_BITMAP_PROPERTIES1 bmProp;
440 Zero(bmProp);
441 bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET|D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
442 bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_IGNORE);
443 pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY);
444 if(!SUCCEEDED(WinErr= pdcDst->CreateBitmapFromDxgiSurface(pDXGISurface,bmProp,&pbmBase))) {
445 Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapBase: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height);
446 } else {
447 pdcDst->SetTarget(pbmBase);
448 }
449 return(Err);
450 }
451
452 // Create a targetable bitmap that can be used for compositing.
453 int PxlShader::CreateBitmapComposite(ID2D1DeviceContext *pdcDst, D2D1_SIZE_U szBitmap, ID2D1Bitmap1 *&pbmComposite) {
454 int Err= ERR_OK;
455 HRESULT WinErr;
456 D2D1_BITMAP_PROPERTIES1 bmProp;
457 Zero(bmProp);
458 bmProp.bitmapOptions= D2D1_BITMAP_OPTIONS_TARGET;
459 bmProp.pixelFormat= PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,D2D1_ALPHA_MODE_PREMULTIPLIED);
460 pdcDst->GetDpi(&bmProp.dpiX,&bmProp.dpiY);
461 if(!SUCCEEDED(WinErr= pdcDst->CreateBitmap(szBitmap,0,0,bmProp,&pbmComposite))) {
462 Err= Warn(ERR_DIRECTX,"PxlShader:CreateBitmapComposite: Unable to create %ux%u bitmap.",szBitmap.width,szBitmap.height);
463 } else {
464 pdcDst->SetTarget(pbmComposite);
465 }
466 return(Err);
467 }
468
469 int PxlShader::CreateEffect(void) {
470 int Err= ERR_OK;
471 HRESULT WinErr;
472 if(!SUCCEEDED(WinErr= MyEffect::Register(pD2Factory))) {
473 Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to register MyEffect. [%X]",WinErr);
474 } else if(!SUCCEEDED(WinErr= pdcDraw->CreateEffect(CLSID_MyEffect,&pEffect))) {
475 Err= Warn(ERR_DIRECTX,"PxlShader:CreateEffect: Unable to create MyEffect. [%X]",WinErr);
476 } else {
477 Print(PRINT_INFO,"PxlShader:CreateEffect: OK");
478 }
479 return(Err);
480 }
481
482 void PxlShader::ReleaseEverything(void) {
483 SafeRelease(pEffect);
484 SafeRelease(pbmSrc2);
485 SafeRelease(pbmSrc1);
486 SafeRelease(pbmImg);
487 SafeRelease(pdcDraw);
488 SafeRelease(pD2Device);
489 SafeRelease(pD2Factory);
490 SafeRelease(pDXGIDevice);
491 SafeRelease(pDXGISurface);
492 SafeRelease(pSwapChain);
493 SafeRelease(pDXGIFactory);
494 }
495
496 /*************************************************************************/
497 /** Draw **/
498 /*************************************************************************/
499 int PxlShader::DrawUpdate(void) {
500 int Err= ERR_OK;
501 HRESULT WinErr;
502 pdcDraw->BeginDraw();
503 pdcDraw->SetTransform(Matrix3x2F::Identity());
504 pdcDraw->SetTarget(pbmSrc1);
505 pdcDraw->Clear(ColorF(ColorF::Black,0));
506 D2D1_RECT_F box= { 0,0,80,60 };
507 pdcDraw->FillRectangle(box,D2Brush(pdcDraw,ColorF(ColorF::Goldenrod)));
508 pdcDraw->SetTarget(pbmSrc2);
509 pdcDraw->Clear(ColorF(ColorF::Black,0));
510 D2D1_ELLIPSE dot= { {50,50}, 50,50 };
511 pdcDraw->FillEllipse(&dot,D2Brush(pdcDraw,ColorF(ColorF::ForestGreen)));
512 pdcDraw->SetTarget(pbmImg);
513 pdcDraw->Clear(ColorF(ColorF::Black,0));
514 pdcDraw->SetTransform(Matrix3x2F::Translation(SizeF(ptBall.x,ptBall.y)));
515 pEffect->SetInput(0,pbmSrc1);
516 pEffect->SetInput(1,pbmSrc2);
517 pdcDraw->DrawImage(pEffect);
518 if(!SUCCEEDED(WinErr= pdcDraw->EndDraw())) {
519 Err= Error(ERR_DIRECTX,"PxlShader:DrawUpdate: EndDraw() failed. [%X]",WinErr);
520 ReleaseEverything();
521 }
522 return(Err);
523 }
524
525 int PxlShader::DrawShow(void) {
526 int Err= ERR_OK;
527 HRESULT WinErr;
528 DXGI_PRESENT_PARAMETERS PresentParm;
529 Zero(PresentParm);
530 if(!SUCCEEDED(WinErr= pSwapChain->Present1(1,0,&PresentParm))) {
531 Err= Warn(ERR_DIRECTX,"PxlShader:DrawShow: Present() failed. [%X]",WinErr);
532 }
533 return(Err);
534 }
535
536 /*************************************************************************/
537 /** MyEffect **/
538 /*************************************************************************/
539 MyEffect::MyEffect(void) {
540 Signature= SIGNATURE_MYEFFECT;
541 ctReference= 1;
542 ctInput= 0;
543 Zero(Constants);
544 Constants.tint[2]= 0.50f;
545 }
546
547 MyEffect::~MyEffect(void) {
548 Signature|= SIGNATURE_INVALID;
549 }
550
551 ULONG MyEffect::Release(void) {
552 if(--ctReference > 0)
553 return(ctReference);
554 delete this;
555 return(0);
556 }
557
558 HRESULT MyEffect::QueryInterface(REFIID riid, void **ppInterface) {
559 HRESULT WinErr= S_OK;
560 void *pInterface= 0;
561 if(riid==__uuidof(ID2D1EffectImpl)) {
562 pInterface= reinterpret_cast<ID2D1EffectImpl*>(this);
563 } else if(riid==__uuidof(ID2D1DrawTransform)) {
564 pInterface= static_cast<ID2D1DrawTransform*>(this);
565 } else if(riid==__uuidof(ID2D1Transform)) {
566 pInterface= static_cast<ID2D1Transform*>(this);
567 } else if(riid==__uuidof(ID2D1TransformNode)) {
568 pInterface= static_cast<ID2D1TransformNode*>(this);
569 } else if(riid==__uuidof(ID2D1ComputeTransform)) {
570 Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a compute transform.");
571 WinErr= E_NOINTERFACE;
572 } else if(riid==__uuidof(ID2D1SourceTransform)) {
573 Print(PRINT_DEBUG,"MyEffect:QueryInterface: I am not a source transform.");
574 WinErr= E_NOINTERFACE;
575 } else if(riid==__uuidof(IUnknown)) {
576 pInterface= this;
577 } else {
578 WinErr= E_NOINTERFACE;
579 }
580 if(ppInterface) {
581 *ppInterface= pInterface;
582 if(pInterface)
583 AddRef();
584 }
585 return(WinErr);
586 }
587
588 HRESULT MyEffect::Register(ID2D1Factory1 *pFactory) {
589 HRESULT WinErr= S_OK;
590 static const PCWSTR pszXml =
591 L"<?xml version='1.0'?>\r\n"
592 L"<Effect>\r\n"
593 L" <!-- System Properties -->\r\n"
594 L" <Property name='DisplayName' type='string' value='FirstShader1'/>\r\n"
595 L" <Property name='Author' type='string' value='nlited systems'/>\r\n"
596 L" <Property name='Category' type='string' value='Experimental'/>\r\n"
597 L" <Property name='Description' type='string' value='My first effect.'/>\r\n"
598 L" <Inputs minimum='0' maximum='2'>\r\n"
599 // Source must be specified.
600 L" <Input name='Source1'/>\r\n"
601 L" <Input name='Source2'/>\r\n"
602 L" </Inputs>\r\n"
603 L" <!-- Custom Properties go here. -->\r\n"
604 L" <Property name='Tint' type='uint32'>\r\n"
605 L" <Property name='DisplayName' type='string' value='Tint'/>\r\n"
606 L" <Property name='Default' type='uint32' value='0'/>\r\n"
607 L" </Property>\r\n"
608 L"</Effect>\r\n"
609 ;
610 static const D2D1_PROPERTY_BINDING Bindings[]= {
611 D2D1_VALUE_TYPE_BINDING(L"Tint",&SetTint,&GetTint)
612 };
613 if(!SUCCEEDED(WinErr= pFactory->RegisterEffectFromString(CLSID_MyEffect,pszXml,Bindings,ARRAYSIZE(Bindings),CreateMyEffect))) {
614 Error(ERR_DIRECTX,"MyEffect:Register: RegisterEffectFromString() failed. [%X]",WinErr);
615 }
616 return(WinErr);
617 }
618
619 HRESULT __stdcall MyEffect::CreateMyEffect(IUnknown **ppEffect) {
620 HRESULT WinErr= S_OK;
621 *ppEffect= static_cast<ID2D1EffectImpl*>(new MyEffect);
622 if(!*ppEffect) {
623 WinErr= E_OUTOFMEMORY;
624 }
625 return(WinErr);
626 }
627
628 HRESULT MyEffect::Initialize(ID2D1EffectContext *_pCtx, ID2D1TransformGraph *pGraph) {
629 HRESULT WinErr= S_OK;
630 ID3DBlob *pCode= 0;
631 ID3DBlob *pError= 0;
632 pCtx= _pCtx;
633 if(!SUCCEEDED(WinErr= D3DReadFileToBlob(L"S:\\Src\\HQ\\Dev\\SB\\Chip\\Bugs\\BugsV1\\Out\\Winx64Debug\\FirstShader.cso",&pCode))) {
634 Warn(ERR_FILE_READ,"MyEffect:Initialize: Unable to read shader. [%X]",WinErr);
635 } else if(!SUCCEEDED(WinErr= pCtx->LoadPixelShader(GUID_MyPixelShader,(BYTE*)pCode->GetBufferPointer(),(UINT32)pCode->GetBufferSize()))) {
636 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to create pixel shader. [%X]",WinErr);
637 } else if(!SUCCEEDED(WinErr= pGraph->AddNode(this))) {
638 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to add Node. [%X]",WinErr);
639 } else if(!SUCCEEDED(WinErr= pGraph->SetOutputNode(this))) {
640 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to set output node. [%X]",WinErr);
641 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(0,this,0))) {
642 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 0. [%X]",WinErr);
643 } else if(!SUCCEEDED(WinErr= pGraph->ConnectToEffectInput(1,this,1))) {
644 Warn(ERR_DIRECTX,"MyEffect:Initialize: Unable to connect input 1. [%X]",WinErr);
645 } else {
646 ctInput= 2;
647 Print(PRINT_INFO,"MyEffect:Initialize: OK.");
648 }
649 SafeRelease(pCode);
650 SafeRelease(pError);
651 return(WinErr);
652 }
653
654 // This is a single-transform, single-node graph, SetGraph() should never be called.
655 HRESULT MyEffect::SetGraph(ID2D1TransformGraph *pGraph) {
656 Warn(ERR_DIRECTX,"MyEffect:SetGraph: Should not be called.");
657 return(E_NOTIMPL);
658 }
659
660 HRESULT MyEffect::SetTint(UINT32 Clr) {
661 Constants.tint[0]= (float)((Clr>>16) & 0xFF)/255.0f;
662 Constants.tint[1]= (float)((Clr>> 8) & 0xFF)/255.0f;
663 Constants.tint[2]= (float)((Clr ) & 0xFF)/255.0f;
664 Constants.tint[3]= (float)((Clr>>24) & 0xFF)/255.0f;
665 return(S_OK);
666 }
667
668 UINT32 MyEffect::GetTint(void) const {
669 UINT32 Clr= 0;
670 Clr|= ((UINT32)(Constants.tint[0]*255.0f) & 0xFF)<<16;
671 Clr|= ((UINT32)(Constants.tint[1]*255.0f) & 0xFF)<< 8;
672 Clr|= ((UINT32)(Constants.tint[2]*255.0f) & 0xFF);
673 Clr|= ((UINT32)(Constants.tint[3]*255.0f) & 0xFF)<<24;
674 return(Clr);
675 }
676
677 HRESULT MyEffect::PrepareForRender(D2D1_CHANGE_TYPE Type) {
678 HRESULT WinErr= S_OK;
679 pDraw->SetPixelShaderConstantBuffer((BYTE*)&Constants,sizeof(Constants));
680 return(WinErr);
681 }
682
683 // ID2D1DrawTransform
684 HRESULT MyEffect::SetDrawInfo(ID2D1DrawInfo *_pDraw) {
685 HRESULT WinErr= S_OK;
686 pDraw= _pDraw;
687 if(!SUCCEEDED(WinErr= pDraw->SetPixelShader(GUID_MyPixelShader))) {
688 Warn(ERR_DIRECTX,"MyEffect:SetDrawInfo: SetPixelShader() failed. [%X]",WinErr);
689 }
690 return(WinErr);
691 }
692
693 HRESULT MyEffect::MapOutputRectToInputRects(const D2D1_RECT_L *prOut, _Out_writes_(ctIn) D2D1_RECT_L *prIn, UINT32 ctIn) const {
694 HRESULT WinErr= S_OK;
695 //Print(PRINT_DEBUG,"MyEffect:MapOutputRectToInputRects: ctIn=%u",ctIn);
696 if(ctIn==0) {
697 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: ctIn is zero?");
698 } else if(ctIn>MAX_INPUT) {
699 Warn(ERR_DIRECTX,"MyEffect:MapOutputRectToInputRects: Only %u inputs defined. [%d]",ctInput,ctIn);
700 WinErr= E_INVALIDARG;
701 } else if(ctIn>0) {
702 prIn[0]= *prOut;
703 for(UINT n1=1;n1<ctIn;n1++) {
704 prIn[n1]= *prOut;
705 }
706 }
707 return(WinErr);
708 }
709
710 IFACEMETHODIMP MyEffect::MapInputRectsToOutputRect(const D2D1_RECT_L *prIn, const D2D1_RECT_L *prInOpaque, UINT32 ctIn, D2D1_RECT_L *prOut, D2D1_RECT_L *prOutOpaque) {
711 HRESULT WinErr= S_OK;
712 //Print(PRINT_DEBUG,"MyEffect:MapInputRectsToOutputRect: ctIn=%u",ctIn);
713 if(ctIn==0) {
714 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: ctIn is zero?");
715 } else if(ctIn>MAX_INPUT) {
716 Warn(ERR_DIRECTX,"MyEffect:MapInputRectsToOutputRect: Only %u inputs defined. [%d]",ctInput,ctIn);
717 WinErr= E_INVALIDARG;
718 } else if(ctIn>0) {
719 *prOut= rIn[0]= prIn[0];
720 for(UINT n1=1;n1<ctIn;n1++) {
721 rIn[n1]= prIn[n1];
722 }
723 Zero(*prOutOpaque);
724 }
725 return(WinErr);
726 }
727
728 IFACEMETHODIMP MyEffect::MapInvalidRect(UINT32 nIn, D2D1_RECT_L rInInvalid, D2D1_RECT_L *prOutInvalid) const {
729 HRESULT WinErr= S_OK;
730 Print(PRINT_DEBUG,"MyEffect:MapInvalidRect:");
731 // Set entire output to invalid
732 *prOutInvalid= rIn[0];
733 return(WinErr);
734 }
735
736 IFACEMETHODIMP_(UINT32) MyEffect::GetInputCount(void) const {
737 return(MAX_INPUT);
738 }
739
740 //EOF: PXLSHADER.CPP
WebV7 (C)2018 nlited | Rendered by tikope in 58.919ms | 3.22.166.101