diff --git a/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp b/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp index de230ebb10..ae77ebd1d9 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/BPFunctions.cpp @@ -32,31 +32,6 @@ const bool renderFog = false; using namespace D3D; -// State translation lookup tables -static const D3DBLEND d3dSrcFactors[8] = -{ - D3DBLEND_ZERO, - D3DBLEND_ONE, - D3DBLEND_DESTCOLOR, - D3DBLEND_INVDESTCOLOR, - D3DBLEND_SRCALPHA, - D3DBLEND_INVSRCALPHA, - D3DBLEND_DESTALPHA, - D3DBLEND_INVDESTALPHA -}; - -static const D3DBLEND d3dDestFactors[8] = -{ - D3DBLEND_ZERO, - D3DBLEND_ONE, - D3DBLEND_SRCCOLOR, - D3DBLEND_INVSRCCOLOR, - D3DBLEND_SRCALPHA, - D3DBLEND_INVSRCALPHA, - D3DBLEND_DESTALPHA, - D3DBLEND_INVDESTALPHA -}; - static const D3DCULL d3dCullModes[4] = { D3DCULL_NONE, @@ -150,42 +125,7 @@ void SetDepthMode(const BPCmd &bp) void SetBlendMode(const BPCmd &bp) { - if (bp.changes & 1) - D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, bpmem.blendmode.blendenable); - - D3DBLEND src = d3dSrcFactors[bpmem.blendmode.srcfactor]; - D3DBLEND dst = d3dDestFactors[bpmem.blendmode.dstfactor]; - - if (bp.changes & 0x700) - D3D::SetRenderState(D3DRS_SRCBLEND, src); - - if (bp.changes & 0xE0) - { - if (!bpmem.blendmode.subtract) - { - D3D::SetRenderState(D3DRS_DESTBLEND, dst); - } - else - { - D3D::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); - } - } - if (bp.changes & 0x800) - { - if (bpmem.blendmode.subtract) - { - D3D::SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); - D3D::SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); - } - else - { - D3D::SetRenderState(D3DRS_SRCBLEND, src); - D3D::SetRenderState(D3DRS_DESTBLEND, dst); - } - - D3D::SetRenderState(D3DRS_BLENDOP, - bpmem.blendmode.subtract ? D3DBLENDOP_SUBTRACT : D3DBLENDOP_ADD); - } + Renderer::SetBlendMode(false); } void SetDitherMode(const BPCmd &bp) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp index 05b2f09932..6ef5bbc892 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp @@ -24,20 +24,33 @@ namespace FBManager { static LPDIRECT3DTEXTURE9 s_efb_color_texture; +static LPDIRECT3DTEXTURE9 s_efb_colorBuffer_texture; +static LPDIRECT3DTEXTURE9 s_efb_depth_texture; +static LPDIRECT3DTEXTURE9 s_efb_depthBuffer_texture; static LPDIRECT3DSURFACE9 s_efb_color_surface; static LPDIRECT3DSURFACE9 s_efb_depth_surface; -static LPDIRECT3DSURFACE9 s_efb_color_OffScreensurface; +static LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer; +static LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer; + +static LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer; +static LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer; static D3DFORMAT s_efb_color_surface_Format; static D3DFORMAT s_efb_depth_surface_Format; #undef CHECK -#define CHECK(hr) if (FAILED(hr)) { PanicAlert("FAIL: " __FUNCTION__); } +#define CHECK(hr,Message) if (FAILED(hr)) { PanicAlert(__FUNCTION__ " FAIL: %s" ,Message); } + + LPDIRECT3DSURFACE9 GetEFBColorRTSurface() { return s_efb_color_surface; } LPDIRECT3DSURFACE9 GetEFBDepthRTSurface() { return s_efb_depth_surface; } -LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface() { return s_efb_color_OffScreensurface; } +LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface() { return s_efb_color_OffScreenReadBuffer; } +LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface() { return s_efb_depth_OffScreenReadBuffer; } + +LPDIRECT3DSURFACE9 GetEFBColorReadSurface() { return s_efb_color_ReadBuffer; } +LPDIRECT3DSURFACE9 GetEFBDepthReadSurface() { return s_efb_depth_ReadBuffer; } D3DFORMAT GetEFBDepthRTSurfaceFormat(){return s_efb_depth_surface_Format;} D3DFORMAT GetEFBColorRTSurfaceFormat(){return s_efb_color_surface_Format;} @@ -47,11 +60,12 @@ LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc) return s_efb_color_texture; } + LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle &sourceRc) { // Depth textures not supported under DX9. We're gonna fake this // with a secondary render target later. - return NULL; + return s_efb_depth_texture; } @@ -59,56 +73,171 @@ LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle &sourceRc) void Create() { + // Simplest possible setup to start with. int target_width = Renderer::GetTargetWidth(); int target_height = Renderer::GetTargetHeight(); s_efb_color_surface_Format = D3DFMT_A8R8G8B8; + //get the framebuffer texture HRESULT hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &s_efb_color_texture, NULL); - CHECK(hr); - + CHECK(hr,"Create Color Texture"); + //get the Surface hr = s_efb_color_texture->GetSurfaceLevel(0, &s_efb_color_surface); - CHECK(hr); - hr = D3D::dev->CreateOffscreenPlainSurface(target_width, target_height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &s_efb_color_OffScreensurface, NULL ); - CHECK(hr); + CHECK(hr,"Get Color Surface"); + //create a one pixel texture to work as a buffer for peeking + hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, &s_efb_colorBuffer_texture, NULL); + if (!FAILED(hr)) + { + //get the surface for the peeking texture + hr = s_efb_colorBuffer_texture->GetSurfaceLevel(0, &s_efb_color_ReadBuffer); + CHECK(hr,"Get Color Pixel Surface"); + //create an offscreen surface that we can lock to retrieve the data + hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &s_efb_color_OffScreenReadBuffer, NULL ); + CHECK(hr,"Create Color offScreen Surface"); + } + //Select Zbuffer format supported by hadware. if (g_ActiveConfig.bEFBAccessEnable) { - s_efb_depth_surface_Format = D3DFMT_D32F_LOCKABLE; + //depth format in prefered order + D3DFORMAT *DepthTexFormats = new D3DFORMAT[7]; + DepthTexFormats[0] = (D3DFORMAT)MAKEFOURCC('D','F','2','4'); + DepthTexFormats[1] = (D3DFORMAT)MAKEFOURCC('I','N','T','Z'); + DepthTexFormats[2] = (D3DFORMAT)MAKEFOURCC('R','A','W','Z'); + DepthTexFormats[3] = (D3DFORMAT)MAKEFOURCC('D','F','1','6'); + DepthTexFormats[4] = D3DFMT_D32F_LOCKABLE; + DepthTexFormats[5] = D3DFMT_D16_LOCKABLE; + DepthTexFormats[6] = D3DFMT_D24X8; + + for(int i = 0;i<4;i++) + { + s_efb_depth_surface_Format = DepthTexFormats[i]; + hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_DEPTHSTENCIL, s_efb_depth_surface_Format, + D3DPOOL_DEFAULT, &s_efb_depth_texture, NULL); + if (!FAILED(hr)) + break; + + } + CHECK(hr,"Create Depth Texture"); + if (!FAILED(hr)) + { + //we found a dept texture suported by hardware so get the surface to draw to + hr = s_efb_depth_texture->GetSurfaceLevel(0, &s_efb_depth_surface); + CHECK(hr,"Get Depth Surface"); + //create a buffer texture for peeking + hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_DEPTHSTENCIL, s_efb_depth_surface_Format, + D3DPOOL_DEFAULT, &s_efb_depthBuffer_texture, NULL); + CHECK(hr,"Create Depth Pixel Texture"); + if (!FAILED(hr)) + { + //texture create correctly so get the surface + hr = s_efb_depthBuffer_texture->GetSurfaceLevel(0, &s_efb_depth_ReadBuffer); + CHECK(hr,"Get Depth Pixel Surface"); + // create an ofscren surface to grab the data + hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, s_efb_depth_surface_Format, D3DPOOL_SYSTEMMEM, &s_efb_depth_OffScreenReadBuffer, NULL ); + CHECK(hr,"Create Depth offscreen Surface"); + if (FAILED(hr)) + { + //no depth in system mem so try vista path to grab depth data + //create a offscreen lockeable surface + hr = D3D::dev->CreateOffscreenPlainSurface(1, 1, D3DFMT_D32F_LOCKABLE, D3DPOOL_DEFAULT, &s_efb_depth_OffScreenReadBuffer, NULL ); + CHECK(hr,"Create Depth D3DFMT_D32F_LOCKABLE offscreen Surface"); + if(s_efb_depth_ReadBuffer) + s_efb_depth_ReadBuffer->Release(); + //this is ugly but is a fast way to test wich path to proceed for peeking + s_efb_depth_ReadBuffer = s_efb_depth_OffScreenReadBuffer; + s_efb_depth_surface_Format = D3DFMT_D32F_LOCKABLE; + } + } + + } + if (!FAILED(hr)) + { + //so far so god, texture depth works so return + delete [] DepthTexFormats; + return; + } + else + { + //no depth texture... cleanup + if(s_efb_depth_ReadBuffer) + s_efb_depth_ReadBuffer->Release(); + s_efb_depth_ReadBuffer = NULL; + + if(s_efb_depth_OffScreenReadBuffer) + s_efb_depth_OffScreenReadBuffer->Release(); + + if(s_efb_depth_surface) + s_efb_depth_surface->Release(); + s_efb_depth_surface = NULL; + + if(s_efb_depthBuffer_texture) + s_efb_depthBuffer_texture->Release(); + s_efb_depthBuffer_texture=NULL; + + if(s_efb_depth_texture) + s_efb_depth_texture->Release(); + s_efb_depth_texture = NULL; + } + // no depth textures... try to create an lockable depth surface + for(int i = 4;i<7;i++) + { + s_efb_depth_surface_Format = DepthTexFormats[i]; + hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, s_efb_depth_surface_Format, + D3DMULTISAMPLE_NONE, 0, FALSE, &s_efb_depth_surface, NULL); + if (!FAILED(hr)) break; + } + s_efb_depth_ReadBuffer = s_efb_depth_surface; + CHECK(hr,"CreateDepthStencilSurface"); + delete [] DepthTexFormats; } else { - s_efb_depth_surface_Format = D3DFMT_D24S8; - } - hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, D3DFMT_D32F_LOCKABLE, + s_efb_depth_surface_Format = D3DFMT_D24X8; + hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, s_efb_depth_surface_Format, D3DMULTISAMPLE_NONE, 0, FALSE, &s_efb_depth_surface, NULL); - if (FAILED(hr)) - { - s_efb_depth_surface_Format = D3DFMT_D16_LOCKABLE; - hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, D3DFMT_D16_LOCKABLE, - D3DMULTISAMPLE_NONE, 0, FALSE, &s_efb_depth_surface, NULL); - if(FAILED(hr)) - { - s_efb_depth_surface_Format = D3DFMT_D24S8; - hr = D3D::dev->CreateDepthStencilSurface(target_width, target_height, D3DFMT_D24S8, - D3DMULTISAMPLE_NONE, 0, FALSE, &s_efb_depth_surface, NULL); - } + CHECK(hr,"CreateDepthStencilSurface"); } - CHECK(hr); } void Destroy() { - if(s_efb_color_OffScreensurface) - s_efb_color_OffScreensurface->Release(); + if(s_efb_depth_ReadBuffer) + s_efb_depth_ReadBuffer->Release(); + s_efb_depth_ReadBuffer = NULL; + + if(s_efb_depth_OffScreenReadBuffer) + s_efb_depth_OffScreenReadBuffer->Release(); if(s_efb_depth_surface) s_efb_depth_surface->Release(); s_efb_depth_surface = NULL; + if(s_efb_depthBuffer_texture) + s_efb_depthBuffer_texture->Release(); + s_efb_depthBuffer_texture=NULL; + + if(s_efb_depth_texture) + s_efb_depth_texture->Release(); + s_efb_depth_texture = NULL; + + if(s_efb_color_OffScreenReadBuffer ) + s_efb_color_OffScreenReadBuffer->Release(); + s_efb_color_OffScreenReadBuffer = NULL; + + if(s_efb_color_ReadBuffer ) + s_efb_color_ReadBuffer->Release(); + s_efb_color_ReadBuffer = NULL; + if(s_efb_color_surface) s_efb_color_surface->Release(); - s_efb_color_surface = NULL; + s_efb_color_surface = NULL; + + if(s_efb_colorBuffer_texture) + s_efb_colorBuffer_texture->Release(); + s_efb_colorBuffer_texture = NULL; if(s_efb_color_texture) s_efb_color_texture->Release(); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h index 59dbd62604..ddf8377df5 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h @@ -38,6 +38,10 @@ LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface(); LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface(); D3DFORMAT GetEFBDepthRTSurfaceFormat(); D3DFORMAT GetEFBColorRTSurfaceFormat(); +LPDIRECT3DSURFACE9 GetEFBColorReadSurface(); +LPDIRECT3DSURFACE9 GetEFBDepthReadSurface(); + + /* diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 7cf3b803d4..8af97dd2ab 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -59,10 +59,37 @@ static int s_recordHeight; static bool s_LastFrameDumped; static bool s_AVIDumping; +static u32 s_blendMode; + #define NUMWNDRES 6 extern int g_Res[NUMWNDRES][2]; char st[32768]; +// State translation lookup tables +static const D3DBLEND d3dSrcFactors[8] = +{ + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_DESTCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_SRCALPHA, + D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTALPHA, + D3DBLEND_INVDESTALPHA +}; + +static const D3DBLEND d3dDestFactors[8] = +{ + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_SRCCOLOR, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_SRCALPHA, + D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTALPHA, + D3DBLEND_INVDESTALPHA +}; + void SetupDeviceObjects() { D3D::font.Init(); @@ -100,7 +127,7 @@ bool Renderer::Init() h_temp = 480; } EmuWindow::SetSize(w_temp, h_temp); - + s_blendMode = 0; int backbuffer_ms_mode = 0; // g_ActiveConfig.iMultisampleMode; sscanf(g_Config.cFSResolution, "%dx%d", &w_temp, &h_temp); @@ -441,24 +468,29 @@ void Renderer::SetColorMask() u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) { - //Get the working buffer and it's format + //Get the working buffer LPDIRECT3DSURFACE9 pBuffer = (type == PEEK_Z || type == POKE_Z) ? FBManager::GetEFBDepthRTSurface() : FBManager::GetEFBColorRTSurface(); - + //get the temporal buffer to move 1pixel data + LPDIRECT3DSURFACE9 RBuffer = (type == PEEK_Z || type == POKE_Z) ? + FBManager::GetEFBDepthReadSurface() : FBManager::GetEFBColorReadSurface(); + //get the memory buffer that can be locked LPDIRECT3DSURFACE9 pOffScreenBuffer = (type == PEEK_Z || type == POKE_Z) ? - FBManager::GetEFBDepthRTSurface() : FBManager::GetEFBColorOffScreenRTSurface(); - - D3DLOCKED_RECT drect; - + FBManager::GetEFBDepthOffScreenRTSurface() : FBManager::GetEFBColorOffScreenRTSurface(); + //get the buffer format D3DFORMAT BufferFormat = (type == PEEK_Z || type == POKE_Z) ? FBManager::GetEFBDepthRTSurfaceFormat() : FBManager::GetEFBColorRTSurfaceFormat(); + + D3DLOCKED_RECT drect; + + //Buffer not found alert if(!pBuffer) { PanicAlert("No %s!", (type == PEEK_Z || type == POKE_Z) ? "Z-Buffer" : "Color EFB"); return 0; } // Z buffer lock not suported: returning - if((type == PEEK_Z || type == POKE_Z) && BufferFormat == D3DFMT_D24S8) + if((type == PEEK_Z || type == POKE_Z) && BufferFormat == D3DFMT_D24X8) { return 0; } @@ -472,7 +504,6 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); - u32 z = 0; float val = 0.0f; HRESULT hr; @@ -484,19 +515,54 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) //lock the buffer - if(!(type == PEEK_Z || type == POKE_Z)) + if(!(BufferFormat == D3DFMT_D32F_LOCKABLE || BufferFormat == D3DFMT_D16_LOCKABLE)) { - hr = D3D::dev->StretchRect(pBuffer,&RectToLock,pOffScreenBuffer,&RectToLock, D3DTEXF_NONE); + //the hard support stretchrect in both color and z so use it + hr = D3D::dev->StretchRect(pBuffer,&RectToLock,RBuffer,NULL, D3DTEXF_NONE); + if(FAILED(hr)) + { + PanicAlert("Unable to stretch data to buffer"); + return 0; + } + //retriebe the pixel data to the local memory buffer + D3D::dev->GetRenderTargetData(RBuffer,pOffScreenBuffer); if(FAILED(hr)) { PanicAlert("Unable to copy data to mem buffer"); return 0; } + //change the rect to lock the entire one pixel buffer + RectToLock.bottom = 1; + RectToLock.left = 0; + RectToLock.right = 1; + RectToLock.top = 0; } - + else + { + //like i say in FramebufferManager this is ugly... using the pointers to decide the peek path.. but it works:) + if(BufferFormat == D3DFMT_D32F_LOCKABLE && RBuffer == pOffScreenBuffer) + { + //we are using vista path so use updateSurface to copy depth data + hr = D3D::dev->UpdateSurface(pBuffer,&RectToLock,pOffScreenBuffer,NULL); + if(FAILED(hr)) + { + PanicAlert("Unable to update data to mem buffer"); + return 0; + } + } + else + { + //we are using lockable depth buffer so change the pointer to lock it directly + pOffScreenBuffer = pBuffer; + } + } + //the surface is good.. lock it if((hr = pOffScreenBuffer->LockRect(&drect, &RectToLock, D3DLOCK_READONLY)) != D3D_OK) + { PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" : hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t"); + return 0; + } switch(type) { case PEEK_Z: @@ -505,16 +571,19 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) { case D3DFMT_D32F_LOCKABLE: val = ((float *)drect.pBits)[0]; + z = ((u32)(val * 0xffffff));// 0xFFFFFFFF; break; + case (D3DFORMAT)MAKEFOURCC('D','F','1','6'): case D3DFMT_D16_LOCKABLE: val = ((float)((u16 *)drect.pBits)[0])/((float)0xFFFF); + z = ((u32)(val * 0xffffff)); break; default: - val = 0; + z = ((u32 *)drect.pBits)[0] >> 8; break; }; // [0.0, 1.0] ==> [0, 0xFFFFFFFF] - z = ((u32)(val * 0xffffff));// 0xFFFFFFFF; + break; } case POKE_Z: @@ -535,17 +604,12 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) } - pBuffer->UnlockRect(); + pOffScreenBuffer->UnlockRect(); - // Scale the 32-bit value returned to a 24-bit - // value (GC uses a 24-bit Z-buffer). // TODO: in RE0 this value is often off by one, which causes lighting to disappear - return z;//z >> 8; + return z; - DEBUGGER_PAUSE_LOG_AT(NEXT_EFB_CMD,true,{printf("AccessEFB, type = %d",type);}); - - return 0; } // mtx.m[0][3] = pMatrix[1]; // -0.5f/s_target_width; <-- fix d3d pixel center? @@ -616,6 +680,45 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE D3D::dev->Clear(0, NULL, clearflags, color,(z & 0xFFFFFF) / float(0xFFFFFF), 0); } +void Renderer::SetBlendMode(bool forceUpdate) +{ + // blend mode bit mask + // 0 - blend enable + // 2 - reverse subtract enable (else add) + // 3-5 - srcRGB function + // 6-8 - dstRGB function + + u32 newval = bpmem.blendmode.subtract << 2; + + if (bpmem.blendmode.subtract) { + newval |= 0x0049; // enable blending src 1 dst 1 + } else if (bpmem.blendmode.blendenable) { + newval |= 1; // enable blending + newval |= bpmem.blendmode.srcfactor << 3; + newval |= bpmem.blendmode.dstfactor << 6; + } + + u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; + + if (changes & 1) { + // blend enable change + D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, (newval & 1)); + + } + + if (changes & 4) { + // subtract enable change + D3D::SetRenderState(D3DRS_BLENDOP, newval & 4 ? D3DBLENDOP_REVSUBTRACT : D3DBLENDOP_ADD); + } + + if (changes & 0x1F8) { + // blend RGB change + D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[(newval >> 3) & 7]); + D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[(newval >> 6) & 7]); + } + + s_blendMode = newval; +}