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 :
#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.
TEXT 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.
TEXT 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.
TEXT 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.
TEXT 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.
TEXT 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.
TEXT 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.
TEXT 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.
The non-overlap regions are dark because I am averaging in the
black pixels. I can fix that...
TEXT 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
Success! I now know how to merge two source bitmaps into a
single output image.
The complete PxlShader app:
TEXT 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
WebV7 (C)2018 nlited | Rendered by tikope in 46.956ms | 18.191.205.149