// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "Direct3DDevice9.hpp" #include "Direct3D9.hpp" #include "Direct3DSurface9.hpp" #include "Direct3DIndexBuffer9.hpp" #include "Direct3DVertexBuffer9.hpp" #include "Direct3DTexture9.hpp" #include "Direct3DVolumeTexture9.hpp" #include "Direct3DCubeTexture9.hpp" #include "Direct3DVertexDeclaration9.hpp" #include "Direct3DSwapChain9.hpp" #include "Direct3DPixelShader9.hpp" #include "Direct3DVertexShader9.hpp" #include "Direct3DStateBlock9.hpp" #include "Direct3DQuery9.hpp" #include "Direct3DVolume9.hpp" #include "Debug.hpp" #include "Capabilities.hpp" #include "Math.hpp" #include "Renderer.hpp" #include "Config.hpp" #include "FrameBuffer.hpp" #include "Clipper.hpp" #include "Configurator.hpp" #include "Timer.hpp" #include "Resource.hpp" #include <assert.h> bool localShaderConstants = true; namespace D3D9 { inline unsigned long FtoDW(float f) { return (unsigned long&)f; } Direct3DDevice9::Direct3DDevice9(const HINSTANCE instance, Direct3D9 *d3d9, unsigned int adapter, D3DDEVTYPE deviceType, HWND focusWindow, unsigned long behaviourFlags, D3DPRESENT_PARAMETERS *presentParameters) : instance(instance), adapter(adapter), d3d9(d3d9), deviceType(deviceType), focusWindow(focusWindow), behaviourFlags(behaviourFlags) { InitializeCriticalSection(&criticalSection); init = true; stateRecorder = 0; d3d9->AddRef(); context = new sw::Context(); renderer = new sw::Renderer(context, sw::Direct3D, false); swapChain = 0; depthStencil = 0; autoDepthStencil = 0; renderTarget[0] = 0; renderTarget[1] = 0; renderTarget[2] = 0; renderTarget[3] = 0; for(int i = 0; i < 16 + 4; i++) { texture[i] = 0; } cursor = 0; Reset(presentParameters); pixelShader = 0; vertexShader = 0; lightsDirty = true; pixelShaderDirty = true; pixelShaderConstantsBDirty = 0; pixelShaderConstantsFDirty = 0; pixelShaderConstantsIDirty = 0; vertexShaderDirty = true; vertexShaderConstantsBDirty = 0; vertexShaderConstantsFDirty = 0; vertexShaderConstantsIDirty = 0; for(int i = 0; i < MAX_VERTEX_INPUTS; i++) { dataStream[i] = 0; streamStride[i] = 0; streamOffset[i] = 0; streamSourceFreq[i] = 1; } indexData = 0; vertexDeclaration = 0; D3DMATERIAL9 material; material.Diffuse.r = 1.0f; material.Diffuse.g = 1.0f; material.Diffuse.b = 1.0f; material.Diffuse.a = 0.0f; material.Ambient.r = 0.0f; material.Ambient.g = 0.0f; material.Ambient.b = 0.0f; material.Ambient.a = 0.0f; material.Emissive.r = 0.0f; material.Emissive.g = 0.0f; material.Emissive.b = 0.0f; material.Emissive.a = 0.0f; material.Specular.r = 0.0f; material.Specular.g = 0.0f; material.Specular.b = 0.0f; material.Specular.a = 0.0f; material.Power = 0.0f; SetMaterial(&material); D3DMATRIX identity = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; SetTransform(D3DTS_VIEW, &identity); SetTransform(D3DTS_PROJECTION, &identity); SetTransform(D3DTS_TEXTURE0, &identity); SetTransform(D3DTS_TEXTURE1, &identity); SetTransform(D3DTS_TEXTURE2, &identity); SetTransform(D3DTS_TEXTURE3, &identity); SetTransform(D3DTS_TEXTURE4, &identity); SetTransform(D3DTS_TEXTURE5, &identity); SetTransform(D3DTS_TEXTURE6, &identity); SetTransform(D3DTS_TEXTURE7, &identity); for(int i = 0; i < 12; i++) { SetTransform(D3DTS_WORLDMATRIX(i), &identity); } for(int i = 0; i < MAX_PIXEL_SHADER_CONST; i++) { float zero[4] = {0, 0, 0, 0}; SetPixelShaderConstantF(i, zero, 1); } for(int i = 0; i < MAX_VERTEX_SHADER_CONST; i++) { float zero[4] = {0, 0, 0, 0}; SetVertexShaderConstantF(i, zero, 1); } for(int i = 0; i < 16; i++) { int zero[4] = {0, 0, 0, 0}; SetPixelShaderConstantI(i, zero, 1); SetVertexShaderConstantI(i, zero, 1); SetPixelShaderConstantB(i, &zero[0], 1); SetVertexShaderConstantB(i, &zero[0], 1); } init = false; if(!(behaviourFlags & D3DCREATE_FPU_PRESERVE)) { configureFPU(); } instancingEnabled = pixelShaderVersionX >= D3DPS_VERSION(3, 0); } Direct3DDevice9::~Direct3DDevice9() { delete renderer; renderer = 0; delete context; context = 0; d3d9->Release(); d3d9 = 0; swapChain->unbind(); swapChain = 0; if(depthStencil) { depthStencil->unbind(); depthStencil = 0; } if(autoDepthStencil) { autoDepthStencil->unbind(); autoDepthStencil = 0; } for(int index = 0; index < 4; index++) { if(renderTarget[index]) { renderTarget[index]->unbind(); renderTarget[index] = 0; } } if(vertexDeclaration) { vertexDeclaration->unbind(); vertexDeclaration = 0; } for(int i = 0; i < 16 + 4; i++) { if(texture[i]) { texture[i]->unbind(); texture[i] = 0; } } for(int i = 0; i < MAX_VERTEX_INPUTS; i++) { if(dataStream[i]) { dataStream[i]->unbind(); dataStream[i] = 0; } } if(indexData) { indexData->unbind(); indexData = 0; } if(pixelShader) { pixelShader->unbind(); pixelShader = 0; } if(vertexShader) { vertexShader->unbind(); vertexShader = 0; } if(stateRecorder) { stateRecorder->unbind(); stateRecorder = 0; } palette.clear(); delete cursor; DeleteCriticalSection(&criticalSection); } long Direct3DDevice9::QueryInterface(const IID &iid, void **object) { CriticalSection cs(this); TRACE("const IID &iid = 0x%0.8p, void **object = 0x%0.8p", iid, object); if(iid == IID_IDirect3DDevice9 || iid == IID_IUnknown) { AddRef(); *object = this; return S_OK; } *object = 0; return NOINTERFACE(iid); } unsigned long Direct3DDevice9::AddRef() { TRACE("void"); return Unknown::AddRef(); } unsigned long Direct3DDevice9::Release() { TRACE("void"); return Unknown::Release(); } long Direct3DDevice9::BeginScene() { CriticalSection cs(this); TRACE("void"); return D3D_OK; } long Direct3DDevice9::BeginStateBlock() { CriticalSection cs(this); TRACE("void"); if(stateRecorder) { return INVALIDCALL(); } stateRecorder = new Direct3DStateBlock9(this, (D3DSTATEBLOCKTYPE)0); if(!stateRecorder) { return OUTOFMEMORY(); } stateRecorder->bind(); return D3D_OK; } long Direct3DDevice9::Clear(unsigned long count, const D3DRECT *rects, unsigned long flags, unsigned long color, float z, unsigned long stencil) { CriticalSection cs(this); TRACE("unsigned long count = %d, const D3DRECT *rects = 0x%0.8p, unsigned long flags = 0x%0.8X, unsigned long color = 0x%0.8X, float z = %f, unsigned long stencil = %d", count, rects, flags, color, z, stencil); if(!rects && count != 0) { return INVALIDCALL(); } if(flags & (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL) && !depthStencil) { return INVALIDCALL(); } if(flags & D3DCLEAR_STENCIL) // Check for stencil component { D3DSURFACE_DESC description; depthStencil->GetDesc(&description); switch(description.Format) { case D3DFMT_D15S1: case D3DFMT_D24S8: case D3DFMT_D24X8: case D3DFMT_D24X4S4: case D3DFMT_D24FS8: case D3DFMT_S8_LOCKABLE: // FIXME: INVALIDCALL when trying to clear depth? case D3DFMT_DF24: case D3DFMT_DF16: case D3DFMT_INTZ: break; case D3DFMT_D16_LOCKABLE: case D3DFMT_D32: case D3DFMT_D16: case D3DFMT_D32F_LOCKABLE: case D3DFMT_D32_LOCKABLE: return INVALIDCALL(); default: ASSERT(false); } } if(!rects) { count = 1; D3DRECT rect; rect.x1 = viewport.X; rect.x2 = viewport.X + viewport.Width; rect.y1 = viewport.Y; rect.y2 = viewport.Y + viewport.Height; rects = ▭ } for(unsigned int i = 0; i < count; i++) { sw::Rect clearRect(rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); clearRect.clip(viewport.X, viewport.Y, viewport.X + viewport.Width, viewport.Y + viewport.Height); if(scissorEnable) { clearRect.clip(scissorRect.left, scissorRect.top, scissorRect.right, scissorRect.bottom); } if(flags & D3DCLEAR_TARGET) { for(int index = 0; index < 4; index++) { if(renderTarget[index]) { D3DSURFACE_DESC description; renderTarget[index]->GetDesc(&description); float rgba[4]; rgba[0] = (float)(color & 0x00FF0000) / 0x00FF0000; rgba[1] = (float)(color & 0x0000FF00) / 0x0000FF00; rgba[2] = (float)(color & 0x000000FF) / 0x000000FF; rgba[3] = (float)(color & 0xFF000000) / 0xFF000000; if(renderState[D3DRS_SRGBWRITEENABLE] != FALSE && index == 0 && Capabilities::isSRGBwritable(description.Format)) { rgba[0] = sw::linearToSRGB(rgba[0]); rgba[1] = sw::linearToSRGB(rgba[1]); rgba[2] = sw::linearToSRGB(rgba[2]); } renderer->clear(rgba, sw::FORMAT_A32B32G32R32F, renderTarget[index], clearRect, 0xF); } } } if(flags & D3DCLEAR_ZBUFFER) { z = sw::clamp01(z); depthStencil->clearDepth(z, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height()); } if(flags & D3DCLEAR_STENCIL) { depthStencil->clearStencil(stencil, 0xFF, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height()); } } return D3D_OK; } long Direct3DDevice9::ColorFill(IDirect3DSurface9 *surface, const RECT *rect, D3DCOLOR color) { CriticalSection cs(this); TRACE("IDirect3DSurface9 *surface = 0x%0.8p, const RECT *rect = 0x%0.8p, D3DCOLOR color = 0x%0.8X", surface, rect, color); if(!surface) { return INVALIDCALL(); } D3DSURFACE_DESC description; surface->GetDesc(&description); if(description.Pool != D3DPOOL_DEFAULT) { return INVALIDCALL(); } if(!rect) { RECT lock; lock.left = 0; lock.top = 0; lock.right = description.Width; lock.bottom = description.Height; rect = &lock; } static_cast<Direct3DSurface9*>(surface)->fill(color, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); return D3D_OK; } long Direct3DDevice9::CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS *presentParameters, IDirect3DSwapChain9 **swapChain) { CriticalSection cs(this); TRACE("D3DPRESENT_PARAMETERS *presentParameters = 0x%0.8p, IDirect3DSwapChain9 **swapChain = 0x%0.8p", presentParameters, swapChain); if(!swapChain) { return INVALIDCALL(); } *swapChain = 0; if(!presentParameters) { return INVALIDCALL(); } if(presentParameters->BackBufferCount > 3) { return INVALIDCALL(); // Maximum of three back buffers } *swapChain = new Direct3DSwapChain9(this, presentParameters); if(!*swapChain) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *swapChain; *swapChain = 0; return OUTOFVIDEOMEMORY(); } (*swapChain)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateCubeTexture(unsigned int edgeLength, unsigned int levels, unsigned long usage, D3DFORMAT format, D3DPOOL pool, IDirect3DCubeTexture9 **cubeTexture, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int edgeLength = %d, unsigned int levels = %d, unsigned long usage = %d, D3DFORMAT format = %d, D3DPOOL pool = %d, IDirect3DCubeTexture9 **cubeTexture = 0x%0.8p, void **sharedHandle = 0x%0.8p", edgeLength, levels, usage, format, pool, cubeTexture, sharedHandle); *cubeTexture = 0; if(edgeLength == 0 || (usage & D3DUSAGE_AUTOGENMIPMAP && levels > 1) || d3d9->CheckDeviceFormat(adapter, deviceType, D3DFMT_X8R8G8B8, usage, D3DRTYPE_CUBETEXTURE, format) != D3D_OK) { return INVALIDCALL(); } *cubeTexture = new Direct3DCubeTexture9(this, edgeLength, levels, usage, format, pool); if(!*cubeTexture) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *cubeTexture; *cubeTexture = 0; return OUTOFVIDEOMEMORY(); } (*cubeTexture)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateDepthStencilSurface(unsigned int width, unsigned int height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multiSample, unsigned long multiSampleQuality, int discard, IDirect3DSurface9 **surface, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int width = %d, unsigned int height = %d, D3DFORMAT format = %d, D3DMULTISAMPLE_TYPE multiSample = %d, unsigned long multiSampleQuality = %d, int discard = %d, IDirect3DSurface9 **surface = 0x%0.8p, void **sharedHandle = 0x%0.8p", width, height, format, multiSample, multiSampleQuality, discard, surface, sharedHandle); *surface = 0; if(width == 0 || height == 0 || d3d9->CheckDeviceFormat(adapter, deviceType, D3DFMT_X8R8G8B8, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, format) != D3D_OK || height > sw::OUTLINE_RESOLUTION) { return INVALIDCALL(); } bool lockable = false; switch(format) { case D3DFMT_D15S1: case D3DFMT_D24S8: case D3DFMT_D24X8: case D3DFMT_D24X4S4: case D3DFMT_D24FS8: case D3DFMT_D32: case D3DFMT_D16: case D3DFMT_DF24: case D3DFMT_DF16: case D3DFMT_INTZ: lockable = false; break; case D3DFMT_S8_LOCKABLE: case D3DFMT_D16_LOCKABLE: case D3DFMT_D32F_LOCKABLE: case D3DFMT_D32_LOCKABLE: lockable = true; break; default: ASSERT(false); } *surface = new Direct3DSurface9(this, this, width, height, format, D3DPOOL_DEFAULT, multiSample, multiSampleQuality, lockable, D3DUSAGE_DEPTHSTENCIL); if(!*surface) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *surface; *surface = 0; return OUTOFVIDEOMEMORY(); } (*surface)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateIndexBuffer(unsigned int length, unsigned long usage, D3DFORMAT format, D3DPOOL pool, IDirect3DIndexBuffer9 **indexBuffer, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int length = %d, unsigned long usage = %d, D3DFORMAT format = %d, D3DPOOL pool = %d, IDirect3DIndexBuffer9 **indexBuffer = 0x%0.8p, void **sharedHandle = 0x%0.8p", length, usage, format, pool, indexBuffer, sharedHandle); *indexBuffer = new Direct3DIndexBuffer9(this, length, usage, format, pool); if(!*indexBuffer) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *indexBuffer; *indexBuffer = 0; return OUTOFVIDEOMEMORY(); } (*indexBuffer)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateOffscreenPlainSurface(unsigned int width, unsigned int height, D3DFORMAT format, D3DPOOL pool, IDirect3DSurface9 **surface, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int width = %d, unsigned int height = %d, D3DFORMAT format = %d, D3DPOOL pool = %d, IDirect3DSurface9 **surface = 0x%0.8p, void **sharedHandle = 0x%0.8p", width, height, format, pool, surface, sharedHandle); *surface = 0; if(width == 0 || height == 0 || d3d9->CheckDeviceFormat(adapter, deviceType, D3DFMT_X8R8G8B8, 0, D3DRTYPE_SURFACE, format) != D3D_OK) // FIXME: Allow all formats supported by runtime/REF { return INVALIDCALL(); } if(pool == D3DPOOL_MANAGED) { return INVALIDCALL(); } *surface = new Direct3DSurface9(this, this, width, height, format, pool, D3DMULTISAMPLE_NONE, 0, true, 0); if(!*surface) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *surface; *surface = 0; return OUTOFVIDEOMEMORY(); } (*surface)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreatePixelShader(const unsigned long *function, IDirect3DPixelShader9 **shader) { CriticalSection cs(this); TRACE("const unsigned long *function = 0x%0.8p, IDirect3DPixelShader9 **shader = 0x%0.8p", function, shader); if(!shader) { return INVALIDCALL(); } *shader = 0; if(!sw::PixelShader::validate(function) || function[0] > pixelShaderVersionX) { return INVALIDCALL(); // Shader contains unsupported operations } *shader = new Direct3DPixelShader9(this, function); if(!*shader) { return OUTOFMEMORY(); } (*shader)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateQuery(D3DQUERYTYPE type, IDirect3DQuery9 **query) { CriticalSection cs(this); TRACE("D3DQUERYTYPE type = %d, IDirect3DQuery9 **query = 0x%0.8p", type, query); if(query == 0) // Support checked { switch(type) { case D3DQUERYTYPE_VCACHE: return D3D_OK; case D3DQUERYTYPE_RESOURCEMANAGER: return NOTAVAILABLE(); case D3DQUERYTYPE_VERTEXSTATS: return NOTAVAILABLE(); case D3DQUERYTYPE_EVENT: return D3D_OK; case D3DQUERYTYPE_OCCLUSION: return D3D_OK; case D3DQUERYTYPE_TIMESTAMP: return D3D_OK; case D3DQUERYTYPE_TIMESTAMPDISJOINT: return D3D_OK; case D3DQUERYTYPE_TIMESTAMPFREQ: return D3D_OK; case D3DQUERYTYPE_PIPELINETIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_INTERFACETIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_VERTEXTIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_PIXELTIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_BANDWIDTHTIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_CACHEUTILIZATION: return NOTAVAILABLE(); default: ASSERT(false); return NOTAVAILABLE(); } } else { switch(type) { case D3DQUERYTYPE_VCACHE: break; case D3DQUERYTYPE_RESOURCEMANAGER: return NOTAVAILABLE(); case D3DQUERYTYPE_VERTEXSTATS: return NOTAVAILABLE(); case D3DQUERYTYPE_EVENT: break; case D3DQUERYTYPE_OCCLUSION: break; case D3DQUERYTYPE_TIMESTAMP: break; case D3DQUERYTYPE_TIMESTAMPDISJOINT: break; case D3DQUERYTYPE_TIMESTAMPFREQ: break; case D3DQUERYTYPE_PIPELINETIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_INTERFACETIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_VERTEXTIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_PIXELTIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_BANDWIDTHTIMINGS: return NOTAVAILABLE(); case D3DQUERYTYPE_CACHEUTILIZATION: return NOTAVAILABLE(); default: ASSERT(false); return NOTAVAILABLE(); } *query = new Direct3DQuery9(this, type); if(!*query) { return OUTOFMEMORY(); } (*query)->AddRef(); return D3D_OK; } } long Direct3DDevice9::CreateRenderTarget(unsigned int width, unsigned int height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multiSample, unsigned long multiSampleQuality, int lockable, IDirect3DSurface9 **surface, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int width = %d, unsigned int height = %d, D3DFORMAT format = %d, D3DMULTISAMPLE_TYPE multiSample = %d, unsigned long multiSampleQuality = %d, int lockable = %d, IDirect3DSurface9 **surface = 0x%0.8p, void **sharedHandle = 0x%0.8p", width, height, format, multiSample, multiSampleQuality, lockable, surface, sharedHandle); *surface = 0; if(width == 0 || height == 0 || d3d9->CheckDeviceFormat(adapter, deviceType, D3DFMT_X8R8G8B8, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, format) != D3D_OK || height > sw::OUTLINE_RESOLUTION) { return INVALIDCALL(); } *surface = new Direct3DSurface9(this, this, width, height, format, D3DPOOL_DEFAULT, multiSample, multiSampleQuality, lockable != FALSE, D3DUSAGE_RENDERTARGET); if(!*surface) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *surface; *surface = 0; return OUTOFVIDEOMEMORY(); } (*surface)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateStateBlock(D3DSTATEBLOCKTYPE type, IDirect3DStateBlock9 **stateBlock) { CriticalSection cs(this); TRACE("D3DSTATEBLOCKTYPE type = %d, IDirect3DStateBlock9 **stateBlock = 0x%0.8p", type, stateBlock); *stateBlock = new Direct3DStateBlock9(this, type); if(!*stateBlock) { return OUTOFMEMORY(); } (*stateBlock)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateTexture(unsigned int width, unsigned int height, unsigned int levels, unsigned long usage, D3DFORMAT format, D3DPOOL pool, IDirect3DTexture9 **texture, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int width = %d, unsigned int height = %d, unsigned int levels = %d, unsigned long usage = %d, D3DFORMAT format = %d, D3DPOOL pool = %d, IDirect3DTexture9 **texture = 0x%0.8p, void **sharedHandle = 0x%0.8p", width, height, levels, usage, format, pool, texture, sharedHandle); *texture = 0; if(width == 0 || height == 0 || (usage & D3DUSAGE_AUTOGENMIPMAP && levels > 1) || d3d9->CheckDeviceFormat(adapter, deviceType, D3DFMT_X8R8G8B8, usage, D3DRTYPE_TEXTURE, format) != D3D_OK) { return INVALIDCALL(); } *texture = new Direct3DTexture9(this, width, height, levels, usage, format, pool); if(!*texture) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *texture; *texture = 0; return OUTOFVIDEOMEMORY(); } (*texture)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateVertexBuffer(unsigned int length, unsigned long usage, unsigned long FVF, D3DPOOL pool, IDirect3DVertexBuffer9 **vertexBuffer, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int length = %d, unsigned long usage = %d, unsigned long FVF = 0x%0.8X, D3DPOOL pool = %d, IDirect3DVertexBuffer9 **vertexBuffer = 0x%0.8p, void **sharedHandle = 0x%0.8p", length, usage, FVF, pool, vertexBuffer, sharedHandle); *vertexBuffer = new Direct3DVertexBuffer9(this, length, usage, FVF, pool); if(!*vertexBuffer) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *vertexBuffer; *vertexBuffer = 0; return OUTOFVIDEOMEMORY(); } (*vertexBuffer)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateVertexDeclaration(const D3DVERTEXELEMENT9 *vertexElements, IDirect3DVertexDeclaration9 **declaration) { CriticalSection cs(this); TRACE("const D3DVERTEXELEMENT9 *vertexElements = 0x%0.8p, IDirect3DVertexDeclaration9 **declaration = 0x%0.8p", vertexElements, declaration); if(!declaration) { return INVALIDCALL(); } const D3DVERTEXELEMENT9 *element = vertexElements; while(element->Stream != 0xFF) { if(element->Type > D3DDECLTYPE_UNUSED) // FIXME: Check other fields too { return FAIL(); } element++; } *declaration = new Direct3DVertexDeclaration9(this, vertexElements); if(!*declaration) { return OUTOFMEMORY(); } (*declaration)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateVertexShader(const unsigned long *function, IDirect3DVertexShader9 **shader) { CriticalSection cs(this); TRACE("const unsigned long *function = 0x%0.8p, IDirect3DVertexShader9 **shader = 0x%0.8p", function, shader); if(!shader) { return INVALIDCALL(); } *shader = 0; if(!sw::VertexShader::validate(function) || function[0] > vertexShaderVersionX) { return INVALIDCALL(); // Shader contains unsupported operations } *shader = new Direct3DVertexShader9(this, function); if(!*shader) { return OUTOFMEMORY(); } (*shader)->AddRef(); return D3D_OK; } long Direct3DDevice9::CreateVolumeTexture(unsigned int width, unsigned int height, unsigned int depth, unsigned int levels, unsigned long usage, D3DFORMAT format, D3DPOOL pool, IDirect3DVolumeTexture9 **volumeTexture, void **sharedHandle) { CriticalSection cs(this); TRACE("unsigned int width = %d, unsigned int height = %d, unsigned int depth = %d, unsigned int levels = %d, unsigned long usage = %d, D3DFORMAT format = %d, D3DPOOL pool = %d, IDirect3DVolumeTexture9 **volumeTexture = 0x%0.8p, void **sharedHandle = 0x%0.8p", width, height, depth, levels, usage, format, pool, volumeTexture, sharedHandle); *volumeTexture = 0; if(width == 0 || height == 0 || depth == 0 || (usage & D3DUSAGE_AUTOGENMIPMAP && levels > 1) || d3d9->CheckDeviceFormat(adapter, deviceType, D3DFMT_X8R8G8B8, usage, D3DRTYPE_VOLUMETEXTURE, format) != D3D_OK) { return INVALIDCALL(); } *volumeTexture = new Direct3DVolumeTexture9(this, width, height, depth, levels, usage, format, pool); if(!*volumeTexture) { return OUTOFMEMORY(); } if(GetAvailableTextureMem() == 0) { delete *volumeTexture; *volumeTexture = 0; return OUTOFVIDEOMEMORY(); } (*volumeTexture)->AddRef(); return D3D_OK; } long Direct3DDevice9::DeletePatch(unsigned int handle) { CriticalSection cs(this); TRACE("unsigned int handle = %d", handle); UNIMPLEMENTED(); return D3D_OK; } long Direct3DDevice9::DrawIndexedPrimitive(D3DPRIMITIVETYPE type, int baseVertexIndex, unsigned int minIndex, unsigned int numVertices, unsigned int startIndex, unsigned int primitiveCount) { CriticalSection cs(this); TRACE("D3DPRIMITIVETYPE type = %d, int baseVertexIndex = %d, unsigned int minIndex = %d, unsigned int numVertices = %d, unsigned int startIndex = %d, unsigned int primitiveCount = %d", type, baseVertexIndex, minIndex, numVertices, startIndex, primitiveCount); if(!indexData) { return INVALIDCALL(); } if(!bindResources(indexData) || !primitiveCount) { return D3D_OK; } unsigned int indexOffset = startIndex * (indexData->is32Bit() ? 4 : 2); // FIXME: Doesn't take stream frequencies into account sw::DrawType drawType; if(indexData->is32Bit()) { switch(type) { case D3DPT_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST32; break; case D3DPT_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST32; break; case D3DPT_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP32; break; case D3DPT_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST32; break; case D3DPT_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP32; break; case D3DPT_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN32; break; default: ASSERT(false); } } else { switch(type) { case D3DPT_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST16; break; case D3DPT_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST16; break; case D3DPT_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP16; break; case D3DPT_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST16; break; case D3DPT_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP16; break; case D3DPT_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN16; break; default: ASSERT(false); } } if((streamSourceFreq[0] & D3DSTREAMSOURCE_INDEXEDDATA) && instanceData()) { int instanceCount = (streamSourceFreq[0] & ~D3DSTREAMSOURCE_INDEXEDDATA); for(int instance = 0; instance < instanceCount; instance++) { bindVertexStreams(baseVertexIndex, true, instance); renderer->draw(drawType, indexOffset, primitiveCount, instance == 0); } } else { bindVertexStreams(baseVertexIndex, false, 0); renderer->draw(drawType, indexOffset, primitiveCount); } return D3D_OK; } long Direct3DDevice9::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE type, unsigned int minIndex, unsigned int numVertices, unsigned int primitiveCount, const void *indexData, D3DFORMAT indexDataFormat, const void *vertexStreamZeroData, unsigned int vertexStreamZeroStride) { CriticalSection cs(this); TRACE("D3DPRIMITIVETYPE type = %d, unsigned int minIndex = %d, unsigned int numVertices = %d, unsigned int primitiveCount = %d, const void *indexData = 0x%0.8p, D3DFORMAT indexDataFormat = %d, const void *vertexStreamZeroData = 0x%0.8p, unsigned int vertexStreamZeroStride = %d", type, minIndex, numVertices, primitiveCount, indexData, indexDataFormat, vertexStreamZeroData, vertexStreamZeroStride); if(!vertexStreamZeroData || !indexData) { return INVALIDCALL(); } int length = (minIndex + numVertices) * vertexStreamZeroStride; Direct3DVertexBuffer9 *vertexBuffer = new Direct3DVertexBuffer9(this, length, 0, 0, D3DPOOL_DEFAULT); void *data; vertexBuffer->Lock(0, 0, &data, 0); memcpy(data, vertexStreamZeroData, length); vertexBuffer->Unlock(); SetStreamSource(0, vertexBuffer, 0, vertexStreamZeroStride); switch(type) { case D3DPT_POINTLIST: length = primitiveCount; break; case D3DPT_LINELIST: length = primitiveCount * 2; break; case D3DPT_LINESTRIP: length = primitiveCount + 1; break; case D3DPT_TRIANGLELIST: length = primitiveCount * 3; break; case D3DPT_TRIANGLESTRIP: length = primitiveCount + 2; break; case D3DPT_TRIANGLEFAN: length = primitiveCount + 2; break; default: ASSERT(false); } length *= indexDataFormat == D3DFMT_INDEX32 ? 4 : 2; Direct3DIndexBuffer9 *indexBuffer = new Direct3DIndexBuffer9(this, length, 0, indexDataFormat, D3DPOOL_DEFAULT); indexBuffer->Lock(0, 0, &data, 0); memcpy(data, indexData, length); indexBuffer->Unlock(); SetIndices(indexBuffer); if(!bindResources(indexBuffer) || !primitiveCount) { vertexBuffer->Release(); return D3D_OK; } sw::DrawType drawType; if(indexDataFormat == D3DFMT_INDEX32) { switch(type) { case D3DPT_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST32; break; case D3DPT_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST32; break; case D3DPT_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP32; break; case D3DPT_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST32; break; case D3DPT_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP32; break; case D3DPT_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN32; break; default: ASSERT(false); } } else { switch(type) { case D3DPT_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST16; break; case D3DPT_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST16; break; case D3DPT_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP16; break; case D3DPT_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST16; break; case D3DPT_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP16; break; case D3DPT_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN16; break; default: ASSERT(false); } } bindVertexStreams(0, false, 0); renderer->draw(drawType, 0, primitiveCount); SetStreamSource(0, 0, 0, 0); SetIndices(0); return D3D_OK; } long Direct3DDevice9::DrawPrimitive(D3DPRIMITIVETYPE primitiveType, unsigned int startVertex, unsigned int primitiveCount) { CriticalSection cs(this); TRACE("D3DPRIMITIVETYPE primitiveType = %d, unsigned int startVertex = %d, unsigned int primitiveCount = %d", primitiveType, startVertex, primitiveCount); if(!bindResources(0) || !primitiveCount) { return D3D_OK; } sw::DrawType drawType; switch(primitiveType) { case D3DPT_POINTLIST: drawType = sw::DRAW_POINTLIST; break; case D3DPT_LINELIST: drawType = sw::DRAW_LINELIST; break; case D3DPT_LINESTRIP: drawType = sw::DRAW_LINESTRIP; break; case D3DPT_TRIANGLELIST: drawType = sw::DRAW_TRIANGLELIST; break; case D3DPT_TRIANGLESTRIP: drawType = sw::DRAW_TRIANGLESTRIP; break; case D3DPT_TRIANGLEFAN: drawType = sw::DRAW_TRIANGLEFAN; break; default: ASSERT(false); } bindVertexStreams(startVertex, false, 0); renderer->draw(drawType, 0, primitiveCount); return D3D_OK; } long Direct3DDevice9::DrawPrimitiveUP(D3DPRIMITIVETYPE primitiveType, unsigned int primitiveCount, const void *vertexStreamZeroData, unsigned int vertexStreamZeroStride) { CriticalSection cs(this); TRACE("D3DPRIMITIVETYPE primitiveType = %d, unsigned int primitiveCount = %d, const void *vertexStreamZeroData = 0x%0.8p, unsigned int vertexStreamZeroStride = %d", primitiveType, primitiveCount, vertexStreamZeroData, vertexStreamZeroStride); if(!vertexStreamZeroData) { return INVALIDCALL(); } IDirect3DVertexBuffer9 *vertexBuffer = 0; int length = 0; switch(primitiveType) { case D3DPT_POINTLIST: length = primitiveCount; break; case D3DPT_LINELIST: length = primitiveCount * 2; break; case D3DPT_LINESTRIP: length = primitiveCount + 1; break; case D3DPT_TRIANGLELIST: length = primitiveCount * 3; break; case D3DPT_TRIANGLESTRIP: length = primitiveCount + 2; break; case D3DPT_TRIANGLEFAN: length = primitiveCount + 2; break; default: ASSERT(false); } length *= vertexStreamZeroStride; CreateVertexBuffer(length, 0, 0, D3DPOOL_DEFAULT, &vertexBuffer, 0); void *data; vertexBuffer->Lock(0, 0, &data, 0); memcpy(data, vertexStreamZeroData, length); vertexBuffer->Unlock(); SetStreamSource(0, vertexBuffer, 0, vertexStreamZeroStride); if(!bindResources(0) || !primitiveCount) { vertexBuffer->Release(); return D3D_OK; } sw::DrawType drawType; switch(primitiveType) { case D3DPT_POINTLIST: drawType = sw::DRAW_POINTLIST; break; case D3DPT_LINELIST: drawType = sw::DRAW_LINELIST; break; case D3DPT_LINESTRIP: drawType = sw::DRAW_LINESTRIP; break; case D3DPT_TRIANGLELIST: drawType = sw::DRAW_TRIANGLELIST; break; case D3DPT_TRIANGLESTRIP: drawType = sw::DRAW_TRIANGLESTRIP; break; case D3DPT_TRIANGLEFAN: drawType = sw::DRAW_TRIANGLEFAN; break; default: ASSERT(false); } bindVertexStreams(0, false, 0); renderer->draw(drawType, 0, primitiveCount); SetStreamSource(0, 0, 0, 0); vertexBuffer->Release(); return D3D_OK; } long Direct3DDevice9::DrawRectPatch(unsigned int handle, const float *numSegs, const D3DRECTPATCH_INFO *rectPatchInfo) { CriticalSection cs(this); TRACE("unsigned int handle = %d, const float *numSegs = 0x%0.8p, const D3DRECTPATCH_INFO *rectPatchInfo = 0x%0.8p", handle, numSegs, rectPatchInfo); if(!numSegs || !rectPatchInfo) { return INVALIDCALL(); } UNIMPLEMENTED(); return D3D_OK; } long Direct3DDevice9::DrawTriPatch(unsigned int handle, const float *numSegs, const D3DTRIPATCH_INFO *triPatchInfo) { CriticalSection cs(this); TRACE("unsigned int handle = %d, const float *numSegs = 0x%0.8p, const D3DTRIPATCH_INFO *triPatchInfo = 0x%0.8p", handle, numSegs, triPatchInfo); if(!numSegs || !triPatchInfo) { return INVALIDCALL(); } UNIMPLEMENTED(); return D3D_OK; } long Direct3DDevice9::EndScene() { CriticalSection cs(this); TRACE("void"); return D3D_OK; } long Direct3DDevice9::EndStateBlock(IDirect3DStateBlock9 **stateBlock) { CriticalSection cs(this); TRACE("IDirect3DStateBlock9 **stateBlock = 0x%0.8p", stateBlock); if(!stateBlock) { return INVALIDCALL(); } *stateBlock = 0; if(!stateRecorder) { return INVALIDCALL(); } *stateBlock = stateRecorder; stateRecorder->AddRef(); stateRecorder->unbind(); stateRecorder = 0; // Stop recording return D3D_OK; } long Direct3DDevice9::EvictManagedResources() { CriticalSection cs(this); TRACE("void"); // UNIMPLEMENTED(); // FIXME return D3D_OK; } unsigned int Direct3DDevice9::GetAvailableTextureMem() { CriticalSection cs(this); TRACE("void"); int availableMemory = textureMemory - Direct3DResource9::getMemoryUsage(); if(availableMemory < 0) availableMemory = 0; // Round to nearest MB return (availableMemory + 0x80000) & 0xFFF00000; } long Direct3DDevice9::GetBackBuffer(unsigned int swapChainIndex, unsigned int backBufferIndex, D3DBACKBUFFER_TYPE type, IDirect3DSurface9 **backBuffer) { CriticalSection cs(this); TRACE("unsigned int swapChainIndex = %d, unsigned int backBufferIndex = %d, D3DBACKBUFFER_TYPE type = %d, IDirect3DSurface9 **backBuffer = 0x%0.8p", swapChainIndex, backBufferIndex, type, backBuffer); if(swapChainIndex >= GetNumberOfSwapChains()) { return INVALIDCALL(); } return swapChain->GetBackBuffer(backBufferIndex, type, backBuffer); } long Direct3DDevice9::GetClipPlane(unsigned long index, float *plane) { CriticalSection cs(this); TRACE("unsigned long index = %d, float *plane = 0x%0.8p", index, plane); if(!plane || index >= 6) { return INVALIDCALL(); } plane[0] = this->plane[index][0]; plane[1] = this->plane[index][1]; plane[2] = this->plane[index][2]; plane[3] = this->plane[index][3]; return D3D_OK; } long Direct3DDevice9::GetClipStatus(D3DCLIPSTATUS9 *clipStatus) { CriticalSection cs(this); TRACE("D3DCLIPSTATUS9 *clipStatus = 0x%0.8p", clipStatus); if(!clipStatus) { return INVALIDCALL(); } *clipStatus = this->clipStatus; return D3D_OK; } long Direct3DDevice9::GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *parameters) { CriticalSection cs(this); TRACE("D3DDEVICE_CREATION_PARAMETERS *parameters = 0x%0.8p", parameters); if(!parameters) { return INVALIDCALL(); } parameters->AdapterOrdinal = adapter; parameters->BehaviorFlags = behaviourFlags; parameters->DeviceType = deviceType; parameters->hFocusWindow = focusWindow; return D3D_OK; } long Direct3DDevice9::GetCurrentTexturePalette(unsigned int *paletteNumber) { CriticalSection cs(this); TRACE("unsigned int *paletteNumber = 0x%0.8p", paletteNumber); if(!paletteNumber) { return INVALIDCALL(); } *paletteNumber = currentPalette; return D3D_OK; } long Direct3DDevice9::GetDepthStencilSurface(IDirect3DSurface9 **depthStencilSurface) { CriticalSection cs(this); TRACE("IDirect3DSurface9 **depthStencilSurface = 0x%0.8p", depthStencilSurface); if(!depthStencilSurface) { return INVALIDCALL(); } *depthStencilSurface = depthStencil; if(depthStencil) { depthStencil->AddRef(); } else { return NOTFOUND(); } return D3D_OK; } long Direct3DDevice9::GetDeviceCaps(D3DCAPS9 *caps) { CriticalSection cs(this); TRACE("D3DCAPS9 *caps = 0x%0.8p", caps); return d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, caps); } long Direct3DDevice9::GetDirect3D(IDirect3D9 **d3d9) { CriticalSection cs(this); TRACE("IDirect3D9 **d3d9 = 0x%0.8p", d3d9); if(!d3d9) { return INVALIDCALL(); } *d3d9 = this->d3d9; this->d3d9->AddRef(); return D3D_OK; } long Direct3DDevice9::GetDisplayMode(unsigned int index, D3DDISPLAYMODE *mode) { CriticalSection cs(this); TRACE("unsigned int index = %d, D3DDISPLAYMODE *mode = 0x%0.8p", index, mode); if(index >= GetNumberOfSwapChains()) { return INVALIDCALL(); } return swapChain->GetDisplayMode(mode); } long Direct3DDevice9::GetFrontBufferData(unsigned int index, IDirect3DSurface9 *destSurface) { CriticalSection cs(this); TRACE("unsigned int index = %d, IDirect3DSurface9 *destSurface = %p", index, destSurface); if(index >= GetNumberOfSwapChains()) { return INVALIDCALL(); } return swapChain->GetFrontBufferData(destSurface); } long Direct3DDevice9::GetFVF(unsigned long *FVF) { CriticalSection cs(this); TRACE("unsigned long *FVF = 0x%0.8p", FVF); if(!FVF) { return INVALIDCALL(); } if(vertexDeclaration) { *FVF = vertexDeclaration->getFVF(); } else { *FVF = 0; } return D3D_OK; } void Direct3DDevice9::GetGammaRamp(unsigned int index, D3DGAMMARAMP *ramp) { CriticalSection cs(this); TRACE("unsigned int index = %d, D3DGAMMARAMP *ramp = 0x%0.8p", index, ramp); if(!ramp || index >= GetNumberOfSwapChains()) { return; } swapChain->getGammaRamp((sw::GammaRamp*)ramp); } long Direct3DDevice9::GetIndices(IDirect3DIndexBuffer9 **indexData) { CriticalSection cs(this); TRACE("IDirect3DIndexBuffer9 **indexData = 0x%0.8p", indexData); if(!indexData) { return INVALIDCALL(); } *indexData = this->indexData; if(this->indexData) { this->indexData->AddRef(); } return D3D_OK; } long Direct3DDevice9::GetLight(unsigned long index, D3DLIGHT9 *light) { CriticalSection cs(this); TRACE("unsigned long index = %d, D3DLIGHT9 *light = 0x%0.8p", index, light); if(!light) { return INVALIDCALL(); } if(!this->light.exists(index)) { return INVALIDCALL(); } *light = this->light[index]; return D3D_OK; } long Direct3DDevice9::GetLightEnable(unsigned long index, int *enable) { CriticalSection cs(this); TRACE("unsigned long index = %d, int *enable = 0x%0.8p", index, enable); if(!enable) { return INVALIDCALL(); } if(!light.exists(index)) { return INVALIDCALL(); } *enable = light[index].enable ? 128 : 0; return D3D_OK; } long Direct3DDevice9::GetMaterial(D3DMATERIAL9 *material) { CriticalSection cs(this); TRACE("D3DMATERIAL9 *material = 0x%0.8p", material); if(!material) { return INVALIDCALL(); } *material = this->material; return D3D_OK; } float Direct3DDevice9::GetNPatchMode() { CriticalSection cs(this); TRACE("void"); return 0.0f; // FIXME: Unimplemented } unsigned int Direct3DDevice9::GetNumberOfSwapChains() { CriticalSection cs(this); TRACE("void"); return 1; } long Direct3DDevice9::GetPaletteEntries(unsigned int paletteNumber, PALETTEENTRY *entries) { CriticalSection cs(this); TRACE("unsigned int paletteNumber = %d, PALETTEENTRY *entries = 0x%0.8p", paletteNumber, entries); if(paletteNumber > 0xFFFF || !entries) { return INVALIDCALL(); } for(int i = 0; i < 256; i++) { entries[i] = palette[paletteNumber].entry[i]; } return D3D_OK; } long Direct3DDevice9::GetPixelShader(IDirect3DPixelShader9 **shader) { CriticalSection cs(this); TRACE("IDirect3DPixelShader9 **shader = 0x%0.8p", shader); if(!shader) { return INVALIDCALL(); } if(pixelShader) { pixelShader->AddRef(); } *shader = pixelShader; return D3D_OK; } long Direct3DDevice9::GetPixelShaderConstantB(unsigned int startRegister, int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } for(unsigned int i = 0; i < count; i++) { constantData[i] = pixelShaderConstantB[startRegister + i]; } return D3D_OK; } long Direct3DDevice9::GetPixelShaderConstantF(unsigned int startRegister, float *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } for(unsigned int i = 0; i < count; i++) { constantData[i * 4 + 0] = pixelShaderConstantF[startRegister + i][0]; constantData[i * 4 + 1] = pixelShaderConstantF[startRegister + i][1]; constantData[i * 4 + 2] = pixelShaderConstantF[startRegister + i][2]; constantData[i * 4 + 3] = pixelShaderConstantF[startRegister + i][3]; } return D3D_OK; } long Direct3DDevice9::GetPixelShaderConstantI(unsigned int startRegister, int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } for(unsigned int i = 0; i < count; i++) { constantData[i * 4 + 0] = pixelShaderConstantI[startRegister + i][0]; constantData[i * 4 + 1] = pixelShaderConstantI[startRegister + i][1]; constantData[i * 4 + 2] = pixelShaderConstantI[startRegister + i][2]; constantData[i * 4 + 3] = pixelShaderConstantI[startRegister + i][3]; } return D3D_OK; } long Direct3DDevice9::GetRasterStatus(unsigned int index, D3DRASTER_STATUS *rasterStatus) { CriticalSection cs(this); TRACE("unsigned int swapChain = %d, D3DRASTER_STATUS *rasterStatus = 0x%0.8p", index, rasterStatus); if(index >= GetNumberOfSwapChains()) { return INVALIDCALL(); } return swapChain->GetRasterStatus(rasterStatus); } long Direct3DDevice9::GetRenderState(D3DRENDERSTATETYPE state, unsigned long *value) { CriticalSection cs(this); TRACE("D3DRENDERSTATETYPE state = %d, unsigned long *value = 0x%0.8p", state, value); if(!value) { return INVALIDCALL(); } *value = renderState[state]; return D3D_OK; } long Direct3DDevice9::GetRenderTarget(unsigned long index, IDirect3DSurface9 **renderTarget) { CriticalSection cs(this); TRACE("unsigned long index = %d, IDirect3DSurface9 **renderTarget = 0x%0.8p", index, renderTarget); if(index >= 4 || !renderTarget) { return INVALIDCALL(); } *renderTarget = 0; if(!this->renderTarget[index]) { return NOTFOUND(); } *renderTarget = this->renderTarget[index]; this->renderTarget[index]->AddRef(); return D3D_OK; } long Direct3DDevice9::GetRenderTargetData(IDirect3DSurface9 *renderTarget, IDirect3DSurface9 *destSurface) { CriticalSection cs(this); TRACE("IDirect3DSurface9 *renderTarget = 0x%0.8p, IDirect3DSurface9 *destSurface = 0x%0.8p", renderTarget, destSurface); if(!renderTarget || !destSurface) { return INVALIDCALL(); } D3DSURFACE_DESC sourceDescription; D3DSURFACE_DESC destinationDescription; renderTarget->GetDesc(&sourceDescription); destSurface->GetDesc(&destinationDescription); if(sourceDescription.Width != destinationDescription.Width || sourceDescription.Height != destinationDescription.Height || sourceDescription.Format != destinationDescription.Format || sourceDescription.MultiSampleType != D3DMULTISAMPLE_NONE) { return INVALIDCALL(); } if(sourceDescription.Format == D3DFMT_A8R8G8B8 || sourceDescription.Format == D3DFMT_X8R8G8B8) { sw::Surface *source = static_cast<Direct3DSurface9*>(renderTarget); sw::Surface *dest = static_cast<Direct3DSurface9*>(destSurface); void *sourceBuffer = source->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); void *destBuffer = dest->lockExternal(0, 0, 0, sw::LOCK_WRITEONLY, sw::PUBLIC); static void (__cdecl *blitFunction)(void *dst, void *src); static sw::Routine *blitRoutine; static sw::BlitState blitState = {}; sw::BlitState update; update.width = sourceDescription.Width; update.height = sourceDescription.Height; update.sourceFormat = sw::FORMAT_A8R8G8B8; update.sourceStride = source->getExternalPitchB(); update.destFormat = sw::FORMAT_A8R8G8B8; update.destStride = dest->getExternalPitchB(); update.cursorHeight = 0; update.cursorWidth = 0; if(memcmp(&blitState, &update, sizeof(sw::BlitState)) != 0) { blitState = update; delete blitRoutine; blitRoutine = sw::FrameBuffer::copyRoutine(blitState); blitFunction = (void(__cdecl*)(void*, void*))blitRoutine->getEntry(); } blitFunction(destBuffer, sourceBuffer); dest->unlockExternal(); source->unlockExternal(); } else { return UpdateSurface(renderTarget, 0, destSurface, 0); } return D3D_OK; } long Direct3DDevice9::GetSamplerState(unsigned long sampler, D3DSAMPLERSTATETYPE state, unsigned long *value) { CriticalSection cs(this); TRACE("unsigned long sampler = %d, D3DSAMPLERSTATETYPE type = %d, unsigned long *value = 0x%0.8p", sampler, state, value); if(!value || state < D3DSAMP_ADDRESSU || state > D3DSAMP_DMAPOFFSET) // FIXME: Set *value to 0? { return INVALIDCALL(); } if((sampler >= 16 && sampler <= D3DDMAPSAMPLER) || sampler > D3DVERTEXTEXTURESAMPLER3) { return INVALIDCALL(); } if(sampler >= D3DVERTEXTEXTURESAMPLER0) { sampler = 16 + (sampler - D3DVERTEXTEXTURESAMPLER0); } *value = samplerState[sampler][state]; return D3D_OK; } long Direct3DDevice9::GetScissorRect(RECT *rect) { CriticalSection cs(this); TRACE("RECT *rect = 0x%0.8p", rect); if(!rect) { return INVALIDCALL(); } *rect = scissorRect; return D3D_OK; } int Direct3DDevice9::GetSoftwareVertexProcessing() { CriticalSection cs(this); TRACE("void"); return softwareVertexProcessing ? TRUE : FALSE; } long Direct3DDevice9::GetStreamSource(unsigned int streamNumber, IDirect3DVertexBuffer9 **streamData, unsigned int *offset, unsigned int *stride) { CriticalSection cs(this); TRACE("unsigned int streamNumber = %d, IDirect3DVertexBuffer9 **streamData = 0x%0.8p, unsigned int *offset = 0x%0.8p, unsigned int *stride = 0x%0.8p", streamNumber, streamData, offset, stride); if(streamNumber >= 16 || !streamData || !offset || !stride) { return INVALIDCALL(); } *streamData = dataStream[streamNumber]; if(dataStream[streamNumber]) { dataStream[streamNumber]->AddRef(); } *offset = streamOffset[streamNumber]; *stride = streamStride[streamNumber]; return D3D_OK; } long Direct3DDevice9::GetStreamSourceFreq(unsigned int streamNumber, unsigned int *divider) { CriticalSection cs(this); TRACE("unsigned int streamNumber = %d, unsigned int *divider = 0x%0.8p", streamNumber, divider); if(streamNumber >= 16 || !divider) { return INVALIDCALL(); } *divider = streamSourceFreq[streamNumber]; return D3D_OK; } long Direct3DDevice9::GetSwapChain(unsigned int index, IDirect3DSwapChain9 **swapChain) { CriticalSection cs(this); TRACE("unsigned int index = %d, IDirect3DSwapChain9 **swapChain = 0x%0.8p", index, swapChain); if(!swapChain || index >= GetNumberOfSwapChains()) { return INVALIDCALL(); } *swapChain = this->swapChain; if(*swapChain) { (*swapChain)->AddRef(); } return D3D_OK; } long Direct3DDevice9::GetTexture(unsigned long sampler, IDirect3DBaseTexture9 **texture) { CriticalSection cs(this); TRACE("unsigned long sampler = %d, IDirect3DBaseTexture9 **texture = 0x%0.8p", sampler, texture); if(!texture) { return INVALIDCALL(); } *texture = 0; if((sampler >= 16 && sampler <= D3DDMAPSAMPLER) || sampler > D3DVERTEXTEXTURESAMPLER3) { return INVALIDCALL(); } *texture = this->texture[sampler]; if(this->texture[sampler]) { this->texture[sampler]->AddRef(); } return D3D_OK; } long Direct3DDevice9::GetTextureStageState(unsigned long stage, D3DTEXTURESTAGESTATETYPE type, unsigned long *value) { CriticalSection cs(this); TRACE("unsigned long stage = %d, D3DTEXTURESTAGESTATETYPE type = %d, unsigned long *value = 0x%0.8p", stage, type, value); if(!value) { return INVALIDCALL(); } *value = textureStageState[stage][type]; return D3D_OK; } long Direct3DDevice9::GetTransform(D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix) { CriticalSection cs(this); TRACE("D3DTRANSFORMSTATETYPE state = %d, D3DMATRIX *matrix = 0x%0.8p", state, matrix); if(!matrix || state < 0 || state > 511) { return INVALIDCALL(); } *matrix = this->matrix[state]; return D3D_OK; } long Direct3DDevice9::GetVertexDeclaration(IDirect3DVertexDeclaration9 **declaration) { CriticalSection cs(this); TRACE("IDirect3DVertexDeclaration9 **declaration = 0x%0.8p", declaration); if(!declaration) { return INVALIDCALL(); } *declaration = vertexDeclaration; if(vertexDeclaration) { vertexDeclaration->AddRef(); } return D3D_OK; } long Direct3DDevice9::GetVertexShader(IDirect3DVertexShader9 **shader) { CriticalSection cs(this); TRACE("IDirect3DVertexShader9 **shader = 0x%0.8p", shader); if(!shader) { return INVALIDCALL(); } *shader = vertexShader; if(vertexShader) { vertexShader->AddRef(); } return D3D_OK; } long Direct3DDevice9::GetVertexShaderConstantB(unsigned int startRegister, int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } for(unsigned int i = 0; i < count; i++) { constantData[i] = vertexShaderConstantB[startRegister + i]; } return D3D_OK; } long Direct3DDevice9::GetVertexShaderConstantF(unsigned int startRegister, float *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } for(unsigned int i = 0; i < count; i++) { constantData[i * 4 + 0] = vertexShaderConstantF[startRegister + i][0]; constantData[i * 4 + 1] = vertexShaderConstantF[startRegister + i][1]; constantData[i * 4 + 2] = vertexShaderConstantF[startRegister + i][2]; constantData[i * 4 + 3] = vertexShaderConstantF[startRegister + i][3]; } return D3D_OK; } long Direct3DDevice9::GetVertexShaderConstantI(unsigned int startRegister, int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } for(unsigned int i = 0; i < count; i++) { constantData[i * 4 + 0] = vertexShaderConstantI[startRegister + i][0]; constantData[i * 4 + 1] = vertexShaderConstantI[startRegister + i][1]; constantData[i * 4 + 2] = vertexShaderConstantI[startRegister + i][2]; constantData[i * 4 + 3] = vertexShaderConstantI[startRegister + i][3]; } return D3D_OK; } long Direct3DDevice9::GetViewport(D3DVIEWPORT9 *viewport) { CriticalSection cs(this); TRACE("D3DVIEWPORT9 *viewport = 0x%0.8p", viewport); if(!viewport) { return INVALIDCALL(); } *viewport = this->viewport; return D3D_OK; } long Direct3DDevice9::LightEnable(unsigned long index, int enable) { CriticalSection cs(this); TRACE("unsigned long index = %d, int enable = %d", index, enable); if(!light.exists(index)) // Insert default light { D3DLIGHT9 light; light.Type = D3DLIGHT_DIRECTIONAL; light.Diffuse.r = 1; light.Diffuse.g = 1; light.Diffuse.b = 1; light.Diffuse.a = 0; light.Specular.r = 0; light.Specular.g = 0; light.Specular.b = 0; light.Specular.a = 0; light.Ambient.r = 0; light.Ambient.g = 0; light.Ambient.b = 0; light.Ambient.a = 0; light.Position.x = 0; light.Position.y = 0; light.Position.z = 0; light.Direction.x = 0; light.Direction.y = 0; light.Direction.z = 1; light.Range = 0; light.Falloff = 0; light.Attenuation0 = 0; light.Attenuation1 = 0; light.Attenuation2 = 0; light.Theta = 0; light.Phi = 0; this->light[index] = light; this->light[index].enable = false; } if(!stateRecorder) { light[index].enable = (enable != FALSE); lightsDirty = true; } else { stateRecorder->lightEnable(index, enable); } return D3D_OK; } long Direct3DDevice9::MultiplyTransform(D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix) { CriticalSection cs(this); TRACE("D3DTRANSFORMSTATETYPE state = %d, const D3DMATRIX *matrix = 0x%0.8p", state, matrix); if(!matrix) { return INVALIDCALL(); } D3DMATRIX *current = &this->matrix[state]; sw::Matrix C(current->_11, current->_21, current->_31, current->_41, current->_12, current->_22, current->_32, current->_42, current->_13, current->_23, current->_33, current->_43, current->_14, current->_24, current->_34, current->_44); sw::Matrix M(matrix->_11, matrix->_21, matrix->_31, matrix->_41, matrix->_12, matrix->_22, matrix->_32, matrix->_42, matrix->_13, matrix->_23, matrix->_33, matrix->_43, matrix->_14, matrix->_24, matrix->_34, matrix->_44); switch(state) { case D3DTS_WORLD: renderer->setModelMatrix(C * M); break; case D3DTS_VIEW: renderer->setViewMatrix(C * M); break; case D3DTS_PROJECTION: renderer->setProjectionMatrix(C * M); break; case D3DTS_TEXTURE0: renderer->setTextureMatrix(0, C * M); break; case D3DTS_TEXTURE1: renderer->setTextureMatrix(1, C * M); break; case D3DTS_TEXTURE2: renderer->setTextureMatrix(2, C * M); break; case D3DTS_TEXTURE3: renderer->setTextureMatrix(3, C * M); break; case D3DTS_TEXTURE4: renderer->setTextureMatrix(4, C * M); break; case D3DTS_TEXTURE5: renderer->setTextureMatrix(5, C * M); break; case D3DTS_TEXTURE6: renderer->setTextureMatrix(6, C * M); break; case D3DTS_TEXTURE7: renderer->setTextureMatrix(7, C * M); break; default: if(state > 256 && state < 512) { renderer->setModelMatrix(C * M, state - 256); } else ASSERT(false); } return D3D_OK; } long Direct3DDevice9::Present(const RECT *sourceRect, const RECT *destRect, HWND destWindowOverride, const RGNDATA *dirtyRegion) { CriticalSection cs(this); TRACE("const RECT *sourceRect = 0x%0.8p, const RECT *destRect = 0x%0.8p, HWND destWindowOverride = %d, const RGNDATA *dirtyRegion = 0x%0.8p", sourceRect, destRect, destWindowOverride, dirtyRegion); return swapChain->Present(sourceRect, destRect, destWindowOverride, dirtyRegion, 0); } long Direct3DDevice9::ProcessVertices(unsigned int srcStartIndex, unsigned int destIndex, unsigned int vertexCount, IDirect3DVertexBuffer9 *destBuffer, IDirect3DVertexDeclaration9 *vertexDeclaration, unsigned long flags) { CriticalSection cs(this); TRACE("unsigned int srcStartIndex = %d, unsigned int destIndex = %d, unsigned int vertexCount = %d, IDirect3DVertexBuffer9 *destBuffer = 0x%0.8p, IDirect3DVertexDeclaration9 *vertexDeclaration = 0x%0.8p, unsigned long flags = %d", srcStartIndex, destIndex, vertexCount, destBuffer, vertexDeclaration, flags); if(!destBuffer) { return INVALIDCALL(); } UNIMPLEMENTED(); return D3D_OK; } long Direct3DDevice9::Reset(D3DPRESENT_PARAMETERS *presentParameters) { CriticalSection cs(this); TRACE("D3DPRESENT_PARAMETERS *presentParameters = 0x%0.8p", presentParameters); if(!presentParameters) { return INVALIDCALL(); } deviceWindow = presentParameters->hDeviceWindow; if(depthStencil) { depthStencil->unbind(); depthStencil = 0; } if(autoDepthStencil) { autoDepthStencil->unbind(); autoDepthStencil = 0; } for(int index = 0; index < 4; index++) { if(renderTarget[index]) { renderTarget[index]->unbind(); renderTarget[index] = 0; } } if(!swapChain) { swapChain = new Direct3DSwapChain9(this, presentParameters); swapChain->bind(); } else { swapChain->reset(presentParameters); } if(presentParameters->EnableAutoDepthStencil != FALSE) { bool lockable = false; switch(presentParameters->AutoDepthStencilFormat) { case D3DFMT_D15S1: case D3DFMT_D24S8: case D3DFMT_D24X8: case D3DFMT_D24X4S4: case D3DFMT_D24FS8: case D3DFMT_D32: case D3DFMT_D16: case D3DFMT_DF24: case D3DFMT_DF16: case D3DFMT_INTZ: lockable = false; break; case D3DFMT_S8_LOCKABLE: case D3DFMT_D16_LOCKABLE: case D3DFMT_D32F_LOCKABLE: case D3DFMT_D32_LOCKABLE: lockable = true; break; default: ASSERT(false); } autoDepthStencil = new Direct3DSurface9(this, this, presentParameters->BackBufferWidth, presentParameters->BackBufferHeight, presentParameters->AutoDepthStencilFormat, D3DPOOL_DEFAULT, presentParameters->MultiSampleType, presentParameters->MultiSampleQuality, lockable, D3DUSAGE_DEPTHSTENCIL); autoDepthStencil->bind(); SetDepthStencilSurface(autoDepthStencil); } IDirect3DSurface9 *renderTarget; swapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &renderTarget); SetRenderTarget(0, renderTarget); renderTarget->Release(); SetRenderTarget(1, 0); SetRenderTarget(2, 0); SetRenderTarget(3, 0); softwareVertexProcessing = (behaviourFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) == D3DCREATE_SOFTWARE_VERTEXPROCESSING; SetRenderState(D3DRS_ZENABLE, presentParameters->EnableAutoDepthStencil != FALSE ? D3DZB_TRUE : D3DZB_FALSE); SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); SetRenderState(D3DRS_ZWRITEENABLE, TRUE); SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); SetRenderState(D3DRS_LASTPIXEL, TRUE); SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); SetRenderState(D3DRS_ALPHAREF, 0); SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS); SetRenderState(D3DRS_DITHERENABLE, FALSE); SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); SetRenderState(D3DRS_FOGENABLE, FALSE); SetRenderState(D3DRS_SPECULARENABLE, FALSE); // SetRenderState(D3DRS_ZVISIBLE, 0); SetRenderState(D3DRS_FOGCOLOR, 0); SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_NONE); SetRenderState(D3DRS_FOGSTART, FtoDW(0.0f)); SetRenderState(D3DRS_FOGEND, FtoDW(1.0f)); SetRenderState(D3DRS_FOGDENSITY, FtoDW(1.0f)); SetRenderState(D3DRS_RANGEFOGENABLE, FALSE); SetRenderState(D3DRS_STENCILENABLE, FALSE); SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); SetRenderState(D3DRS_STENCILREF, 0); SetRenderState(D3DRS_STENCILMASK, 0xFFFFFFFF); SetRenderState(D3DRS_STENCILWRITEMASK, 0xFFFFFFFF); SetRenderState(D3DRS_TEXTUREFACTOR, 0xFFFFFFFF); SetRenderState(D3DRS_WRAP0, 0); SetRenderState(D3DRS_WRAP1, 0); SetRenderState(D3DRS_WRAP2, 0); SetRenderState(D3DRS_WRAP3, 0); SetRenderState(D3DRS_WRAP4, 0); SetRenderState(D3DRS_WRAP5, 0); SetRenderState(D3DRS_WRAP6, 0); SetRenderState(D3DRS_WRAP7, 0); SetRenderState(D3DRS_CLIPPING, TRUE); SetRenderState(D3DRS_LIGHTING, TRUE); SetRenderState(D3DRS_AMBIENT, 0); SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); SetRenderState(D3DRS_COLORVERTEX, TRUE); SetRenderState(D3DRS_LOCALVIEWER, TRUE); SetRenderState(D3DRS_NORMALIZENORMALS, FALSE); SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2); SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL); SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE); SetRenderState(D3DRS_CLIPPLANEENABLE, 0); SetRenderState(D3DRS_POINTSIZE, FtoDW(1.0f)); SetRenderState(D3DRS_POINTSIZE_MIN, FtoDW(1.0f)); SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE); SetRenderState(D3DRS_POINTSCALEENABLE, FALSE); SetRenderState(D3DRS_POINTSCALE_A, FtoDW(1.0f)); SetRenderState(D3DRS_POINTSCALE_B, FtoDW(0.0f)); SetRenderState(D3DRS_POINTSCALE_C, FtoDW(0.0f)); SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); SetRenderState(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE); SetRenderState(D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE); SetRenderState(D3DRS_POINTSIZE_MAX, FtoDW(64.0f)); SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); SetRenderState(D3DRS_COLORWRITEENABLE, 0x0000000F); SetRenderState(D3DRS_TWEENFACTOR, FtoDW(0.0f)); SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); SetRenderState(D3DRS_POSITIONDEGREE, D3DDEGREE_CUBIC); SetRenderState(D3DRS_NORMALDEGREE, D3DDEGREE_LINEAR); SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, FtoDW(0.0f)); SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, FALSE); SetRenderState(D3DRS_MINTESSELLATIONLEVEL, FtoDW(1.0f)); SetRenderState(D3DRS_MAXTESSELLATIONLEVEL, FtoDW(1.0f)); SetRenderState(D3DRS_ADAPTIVETESS_X, FtoDW(0.0f)); SetRenderState(D3DRS_ADAPTIVETESS_Y, FtoDW(0.0f)); SetRenderState(D3DRS_ADAPTIVETESS_Z, FtoDW(1.0f)); SetRenderState(D3DRS_ADAPTIVETESS_W, FtoDW(0.0f)); SetRenderState(D3DRS_ENABLEADAPTIVETESSELLATION, FALSE); SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); SetRenderState(D3DRS_CCW_STENCILFAIL, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_CCW_STENCILZFAIL, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_CCW_STENCILPASS, D3DSTENCILOP_KEEP); SetRenderState(D3DRS_CCW_STENCILFUNC, D3DCMP_ALWAYS); SetRenderState(D3DRS_COLORWRITEENABLE1, 0x0000000F); SetRenderState(D3DRS_COLORWRITEENABLE2, 0x0000000F); SetRenderState(D3DRS_COLORWRITEENABLE3, 0x0000000F); SetRenderState(D3DRS_BLENDFACTOR, 0xFFFFFFFF); SetRenderState(D3DRS_SRGBWRITEENABLE, 0); SetRenderState(D3DRS_DEPTHBIAS, FtoDW(0.0f)); SetRenderState(D3DRS_WRAP8, 0); SetRenderState(D3DRS_WRAP9, 0); SetRenderState(D3DRS_WRAP10, 0); SetRenderState(D3DRS_WRAP11, 0); SetRenderState(D3DRS_WRAP12, 0); SetRenderState(D3DRS_WRAP13, 0); SetRenderState(D3DRS_WRAP14, 0); SetRenderState(D3DRS_WRAP15, 0); SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_ZERO); SetRenderState(D3DRS_BLENDOPALPHA, D3DBLENDOP_ADD); for(int i = 0; i < 8; i++) { SetTextureStageState(i, D3DTSS_COLOROP, i == 0 ? D3DTOP_MODULATE : D3DTOP_DISABLE); SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT); SetTextureStageState(i, D3DTSS_ALPHAOP, i == 0 ? D3DTOP_SELECTARG1 : D3DTOP_DISABLE); SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT); SetTextureStageState(i, D3DTSS_BUMPENVMAT00, FtoDW(0.0f)); SetTextureStageState(i, D3DTSS_BUMPENVMAT01, FtoDW(0.0f)); SetTextureStageState(i, D3DTSS_BUMPENVMAT10, FtoDW(0.0f)); SetTextureStageState(i, D3DTSS_BUMPENVMAT11, FtoDW(0.0f)); SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, i); SetTextureStageState(i, D3DTSS_BUMPENVLSCALE, FtoDW(0.0f)); SetTextureStageState(i, D3DTSS_BUMPENVLOFFSET, FtoDW(0.0f)); SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); SetTextureStageState(i, D3DTSS_COLORARG0, D3DTA_CURRENT); SetTextureStageState(i, D3DTSS_ALPHAARG0, D3DTA_CURRENT); SetTextureStageState(i, D3DTSS_RESULTARG, D3DTA_CURRENT); SetTextureStageState(i, D3DTSS_CONSTANT, 0x00000000); } for(int i = 0; i <= D3DVERTEXTEXTURESAMPLER3; i = (i != 15) ? (i + 1) : D3DVERTEXTEXTURESAMPLER0) { SetTexture(i, 0); SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); SetSamplerState(i, D3DSAMP_ADDRESSW, D3DTADDRESS_WRAP); SetSamplerState(i, D3DSAMP_BORDERCOLOR, 0x00000000); SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_POINT); SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_POINT); SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_NONE); SetSamplerState(i, D3DSAMP_MIPMAPLODBIAS, 0); SetSamplerState(i, D3DSAMP_MAXMIPLEVEL, 0); SetSamplerState(i, D3DSAMP_MAXANISOTROPY, 1); SetSamplerState(i, D3DSAMP_SRGBTEXTURE, 0); SetSamplerState(i, D3DSAMP_ELEMENTINDEX, 0); SetSamplerState(i, D3DSAMP_DMAPOFFSET, 0); } for(int i = 0; i < 6; i++) { float plane[4] = {0, 0, 0, 0}; SetClipPlane(i, plane); } currentPalette = 0xFFFF; ShowCursor(FALSE); delete cursor; cursor = 0; return D3D_OK; } long Direct3DDevice9::SetClipPlane(unsigned long index, const float *plane) { CriticalSection cs(this); TRACE("unsigned long index = %d, const float *plane = 0x%0.8p", index, plane); if(!plane || index >= 6) { return INVALIDCALL(); } if(!stateRecorder) { this->plane[index][0] = plane[0]; this->plane[index][1] = plane[1]; this->plane[index][2] = plane[2]; this->plane[index][3] = plane[3]; renderer->setClipPlane(index, plane); } else { stateRecorder->setClipPlane(index, plane); } return D3D_OK; } long Direct3DDevice9::SetClipStatus(const D3DCLIPSTATUS9 *clipStatus) { CriticalSection cs(this); TRACE("const D3DCLIPSTATUS9 *clipStatus = 0x%0.8p", clipStatus); if(!clipStatus) { return INVALIDCALL(); } this->clipStatus = *clipStatus; UNIMPLEMENTED(); return D3D_OK; } long Direct3DDevice9::SetCurrentTexturePalette(unsigned int paletteNumber) { CriticalSection cs(this); TRACE("unsigned int paletteNumber = %d", paletteNumber); if(paletteNumber > 0xFFFF || palette.find(paletteNumber) == palette.end()) { return INVALIDCALL(); } if(!stateRecorder) { currentPalette = paletteNumber; sw::Surface::setTexturePalette((unsigned int*)&palette[currentPalette]); } else { stateRecorder->setCurrentTexturePalette(paletteNumber); } return D3D_OK; } void Direct3DDevice9::SetCursorPosition(int x, int y, unsigned long flags) { CriticalSection cs(this); TRACE("int x = %d, int y = %d, unsigned long flags = 0x%0.8X", x, y, flags); POINT point = {x, y}; HWND window = deviceWindow ? deviceWindow : focusWindow; ScreenToClient(window, &point); sw::FrameBuffer::setCursorPosition(point.x, point.y); } long Direct3DDevice9::SetCursorProperties(unsigned int x0, unsigned int y0, IDirect3DSurface9 *cursorBitmap) { CriticalSection cs(this); TRACE("unsigned int x0 = %d, unsigned int y0 = %d, IDirect3DSurface9 *cursorBitmap = 0x%0.8p", x0, y0, cursorBitmap); if(!cursorBitmap) { return INVALIDCALL(); } sw::Surface *cursorSurface = static_cast<Direct3DSurface9*>(cursorBitmap); int width = cursorSurface->getWidth(); int height = cursorSurface->getHeight(); void *bitmap = cursorSurface->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); delete cursor; cursor = sw::Surface::create(nullptr, width, height, 1, 0, 1, sw::FORMAT_A8R8G8B8, false, false); void *buffer = cursor->lockExternal(0, 0, 0, sw::LOCK_DISCARD, sw::PUBLIC); memcpy(buffer, bitmap, width * height * sizeof(unsigned int)); cursor->unlockExternal(); cursorSurface->unlockExternal(); if(showCursor) { sw::FrameBuffer::setCursorImage(cursor); } else { sw::FrameBuffer::setCursorImage(nullptr); } sw::FrameBuffer::setCursorOrigin(x0, y0); return D3D_OK; } long Direct3DDevice9::SetDepthStencilSurface(IDirect3DSurface9 *iDepthStencil) { CriticalSection cs(this); TRACE("IDirect3DSurface9 *newDepthStencil = 0x%0.8p", iDepthStencil); Direct3DSurface9 *depthStencil = static_cast<Direct3DSurface9*>(iDepthStencil); if(this->depthStencil == depthStencil) { return D3D_OK; } if(depthStencil) { depthStencil->bind(); } if(this->depthStencil) { this->depthStencil->unbind(); } this->depthStencil = depthStencil; renderer->setDepthBuffer(depthStencil); renderer->setStencilBuffer(depthStencil); return D3D_OK; } long Direct3DDevice9::SetDialogBoxMode(int enableDialogs) { CriticalSection cs(this); TRACE("int enableDialogs = %d", enableDialogs); UNIMPLEMENTED(); return D3D_OK; } long Direct3DDevice9::SetFVF(unsigned long FVF) { CriticalSection cs(this); TRACE("unsigned long FVF = 0x%0.8X", FVF); if(!stateRecorder) { if(FVF != 0 || !this->vertexDeclaration) { Direct3DVertexDeclaration9 *vertexDeclaration = new Direct3DVertexDeclaration9(this, FVF); vertexDeclaration->bind(); if(this->vertexDeclaration) { this->vertexDeclaration->unbind(); } this->vertexDeclaration = vertexDeclaration; } } else { stateRecorder->setFVF(FVF); } return D3D_OK; } void Direct3DDevice9::SetGammaRamp(unsigned int index, unsigned long flags, const D3DGAMMARAMP *ramp) { CriticalSection cs(this); TRACE("unsigned int index = %d, unsigned long flags = 0x%0.8X, const D3DGAMMARAMP *ramp = 0x%0.8p", index, flags, ramp); if(!ramp || index >= GetNumberOfSwapChains()) { return; } swapChain->setGammaRamp((sw::GammaRamp*)ramp, flags & D3DSGR_CALIBRATE); } long Direct3DDevice9::SetIndices(IDirect3DIndexBuffer9* iIndexBuffer) { CriticalSection cs(this); TRACE("IDirect3DIndexBuffer9* indexData = 0x%0.8p", iIndexBuffer); Direct3DIndexBuffer9 *indexBuffer = static_cast<Direct3DIndexBuffer9*>(iIndexBuffer); if(!stateRecorder) { if(this->indexData == indexBuffer) { return D3D_OK; } if(indexBuffer) { indexBuffer->bind(); } if(this->indexData) { this->indexData->unbind(); } this->indexData = indexBuffer; } else { stateRecorder->setIndices(indexBuffer); } return D3D_OK; } long Direct3DDevice9::SetLight(unsigned long index, const D3DLIGHT9 *light) { CriticalSection cs(this); TRACE("unsigned long index = %d, const D3DLIGHT9 *light = 0x%0.8p", index, light); if(!light) { return INVALIDCALL(); } if(!stateRecorder) { this->light[index] = *light; lightsDirty = true; } else { stateRecorder->setLight(index, light); } return D3D_OK; } long Direct3DDevice9::SetMaterial(const D3DMATERIAL9 *material) { CriticalSection cs(this); TRACE("const D3DMATERIAL9 *material = 0x%0.8p", material); if(!material) { return INVALIDCALL(); // FIXME: Correct behaviour? } if(!stateRecorder) { this->material = *material; renderer->setMaterialAmbient(sw::Color<float>(material->Ambient.r, material->Ambient.g, material->Ambient.b, material->Ambient.a)); renderer->setMaterialDiffuse(sw::Color<float>(material->Diffuse.r, material->Diffuse.g, material->Diffuse.b, material->Diffuse.a)); renderer->setMaterialEmission(sw::Color<float>(material->Emissive.r, material->Emissive.g, material->Emissive.b, material->Emissive.a)); renderer->setMaterialShininess(material->Power); renderer->setMaterialSpecular(sw::Color<float>(material->Specular.r, material->Specular.g, material->Specular.b, material->Specular.a)); } else { stateRecorder->setMaterial(material); } return D3D_OK; } long Direct3DDevice9::SetNPatchMode(float segments) { CriticalSection cs(this); TRACE("float segments = %f", segments); if(!stateRecorder) { if(segments < 1) { // NOTE: Disable } else { UNIMPLEMENTED(); } } else { stateRecorder->setNPatchMode(segments); } return D3D_OK; } long Direct3DDevice9::SetPaletteEntries(unsigned int paletteNumber, const PALETTEENTRY *entries) { CriticalSection cs(this); TRACE("unsigned int paletteNumber = %d, const PALETTEENTRY *entries = 0x%0.8p", paletteNumber, entries); if(paletteNumber > 0xFFFF || !entries) { return INVALIDCALL(); } for(int i = 0; i < 256; i++) { palette[paletteNumber].entry[i] = entries[i]; } if(paletteNumber == currentPalette) { sw::Surface::setTexturePalette((unsigned int*)&palette[currentPalette]); } return D3D_OK; } long Direct3DDevice9::SetPixelShader(IDirect3DPixelShader9 *iPixelShader) { CriticalSection cs(this); TRACE("IDirect3DPixelShader9 *shader = 0x%0.8p", iPixelShader); Direct3DPixelShader9 *pixelShader = static_cast<Direct3DPixelShader9*>(iPixelShader); if(!stateRecorder) { if(this->pixelShader == pixelShader) { return D3D_OK; } if(pixelShader) { pixelShader->bind(); } if(this->pixelShader) { this->pixelShader->unbind(); } this->pixelShader = pixelShader; pixelShaderDirty = true; } else { stateRecorder->setPixelShader(pixelShader); } return D3D_OK; } long Direct3DDevice9::SetPixelShaderConstantB(unsigned int startRegister, const int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!stateRecorder) { for(unsigned int i = 0; i < count && startRegister + i < 16; i++) { pixelShaderConstantB[startRegister + i] = constantData[i]; } pixelShaderConstantsBDirty = sw::max(startRegister + count, pixelShaderConstantsBDirty); pixelShaderDirty = true; // Reload DEF constants } else { stateRecorder->setPixelShaderConstantB(startRegister, constantData, count); } return D3D_OK; } long Direct3DDevice9::SetPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!stateRecorder) { for(unsigned int i = 0; i < count && startRegister + i < MAX_PIXEL_SHADER_CONST; i++) { pixelShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0]; pixelShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1]; pixelShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2]; pixelShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3]; } pixelShaderConstantsFDirty = sw::max(startRegister + count, pixelShaderConstantsFDirty); pixelShaderDirty = true; // Reload DEF constants } else { stateRecorder->setPixelShaderConstantF(startRegister, constantData, count); } return D3D_OK; } long Direct3DDevice9::SetPixelShaderConstantI(unsigned int startRegister, const int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!stateRecorder) { for(unsigned int i = 0; i < count && startRegister + i < 16; i++) { pixelShaderConstantI[startRegister + i][0] = constantData[i * 4 + 0]; pixelShaderConstantI[startRegister + i][1] = constantData[i * 4 + 1]; pixelShaderConstantI[startRegister + i][2] = constantData[i * 4 + 2]; pixelShaderConstantI[startRegister + i][3] = constantData[i * 4 + 3]; } pixelShaderConstantsIDirty = sw::max(startRegister + count, pixelShaderConstantsIDirty); pixelShaderDirty = true; // Reload DEF constants } else { stateRecorder->setPixelShaderConstantI(startRegister, constantData, count); } return D3D_OK; } long Direct3DDevice9::SetRenderState(D3DRENDERSTATETYPE state, unsigned long value) { CriticalSection cs(this); TRACE("D3DRENDERSTATETYPE state = %d, unsigned long value = %d", state, value); if(state < D3DRS_ZENABLE || state > D3DRS_BLENDOPALPHA) { return D3D_OK; // FIXME: Warning } if(!stateRecorder) { if(!init && renderState[state] == value) { return D3D_OK; } renderState[state] = value; switch(state) { case D3DRS_ZENABLE: switch(value) { case D3DZB_TRUE: case D3DZB_USEW: renderer->setDepthBufferEnable(true); break; case D3DZB_FALSE: renderer->setDepthBufferEnable(false); break; default: ASSERT(false); } break; case D3DRS_FILLMODE: switch(value) { case D3DFILL_POINT: renderer->setFillMode(sw::FILL_VERTEX); break; case D3DFILL_WIREFRAME: renderer->setFillMode(sw::FILL_WIREFRAME); break; case D3DFILL_SOLID: renderer->setFillMode(sw::FILL_SOLID); break; default: ASSERT(false); } break; case D3DRS_SHADEMODE: switch(value) { case D3DSHADE_FLAT: renderer->setShadingMode(sw::SHADING_FLAT); break; case D3DSHADE_GOURAUD: renderer->setShadingMode(sw::SHADING_GOURAUD); break; case D3DSHADE_PHONG: break; default: ASSERT(false); } break; case D3DRS_ZWRITEENABLE: renderer->setDepthWriteEnable(value != FALSE); break; case D3DRS_ALPHATESTENABLE: renderer->setAlphaTestEnable(value != FALSE); break; case D3DRS_LASTPIXEL: // if(!init) UNIMPLEMENTED(); // FIXME break; case D3DRS_SRCBLEND: switch(value) { case D3DBLEND_ZERO: renderer->setSourceBlendFactor(sw::BLEND_ZERO); break; case D3DBLEND_ONE: renderer->setSourceBlendFactor(sw::BLEND_ONE); break; case D3DBLEND_SRCCOLOR: renderer->setSourceBlendFactor(sw::BLEND_SOURCE); break; case D3DBLEND_INVSRCCOLOR: renderer->setSourceBlendFactor(sw::BLEND_INVSOURCE); break; case D3DBLEND_SRCALPHA: renderer->setSourceBlendFactor(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_INVSRCALPHA: renderer->setSourceBlendFactor(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_DESTALPHA: renderer->setSourceBlendFactor(sw::BLEND_DESTALPHA); break; case D3DBLEND_INVDESTALPHA: renderer->setSourceBlendFactor(sw::BLEND_INVDESTALPHA); break; case D3DBLEND_DESTCOLOR: renderer->setSourceBlendFactor(sw::BLEND_DEST); break; case D3DBLEND_INVDESTCOLOR: renderer->setSourceBlendFactor(sw::BLEND_INVDEST); break; case D3DBLEND_SRCALPHASAT: renderer->setSourceBlendFactor(sw::BLEND_SRCALPHASAT); break; case D3DBLEND_BOTHSRCALPHA: renderer->setSourceBlendFactor(sw::BLEND_SOURCEALPHA); renderer->setDestBlendFactor(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_BOTHINVSRCALPHA: renderer->setSourceBlendFactor(sw::BLEND_INVSOURCEALPHA); renderer->setDestBlendFactor(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_BLENDFACTOR: renderer->setSourceBlendFactor(sw::BLEND_CONSTANT); break; case D3DBLEND_INVBLENDFACTOR: renderer->setSourceBlendFactor(sw::BLEND_INVCONSTANT); break; default: ASSERT(false); } break; case D3DRS_DESTBLEND: switch(value) { case D3DBLEND_ZERO: renderer->setDestBlendFactor(sw::BLEND_ZERO); break; case D3DBLEND_ONE: renderer->setDestBlendFactor(sw::BLEND_ONE); break; case D3DBLEND_SRCCOLOR: renderer->setDestBlendFactor(sw::BLEND_SOURCE); break; case D3DBLEND_INVSRCCOLOR: renderer->setDestBlendFactor(sw::BLEND_INVSOURCE); break; case D3DBLEND_SRCALPHA: renderer->setDestBlendFactor(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_INVSRCALPHA: renderer->setDestBlendFactor(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_DESTALPHA: renderer->setDestBlendFactor(sw::BLEND_DESTALPHA); break; case D3DBLEND_INVDESTALPHA: renderer->setDestBlendFactor(sw::BLEND_INVDESTALPHA); break; case D3DBLEND_DESTCOLOR: renderer->setDestBlendFactor(sw::BLEND_DEST); break; case D3DBLEND_INVDESTCOLOR: renderer->setDestBlendFactor(sw::BLEND_INVDEST); break; case D3DBLEND_SRCALPHASAT: renderer->setDestBlendFactor(sw::BLEND_SRCALPHASAT); break; case D3DBLEND_BOTHSRCALPHA: renderer->setSourceBlendFactor(sw::BLEND_SOURCEALPHA); renderer->setDestBlendFactor(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_BOTHINVSRCALPHA: renderer->setSourceBlendFactor(sw::BLEND_INVSOURCEALPHA); renderer->setDestBlendFactor(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_BLENDFACTOR: renderer->setDestBlendFactor(sw::BLEND_CONSTANT); break; case D3DBLEND_INVBLENDFACTOR: renderer->setDestBlendFactor(sw::BLEND_INVCONSTANT); break; default: ASSERT(false); } break; case D3DRS_CULLMODE: switch(value) { case D3DCULL_NONE: renderer->setCullMode(sw::CULL_NONE, true); break; case D3DCULL_CCW: renderer->setCullMode(sw::CULL_COUNTERCLOCKWISE, true); break; case D3DCULL_CW: renderer->setCullMode(sw::CULL_CLOCKWISE, true); break; default: ASSERT(false); } break; case D3DRS_ZFUNC: switch(value) { case D3DCMP_NEVER: renderer->setDepthCompare(sw::DEPTH_NEVER); break; case D3DCMP_LESS: renderer->setDepthCompare(sw::DEPTH_LESS); break; case D3DCMP_EQUAL: renderer->setDepthCompare(sw::DEPTH_EQUAL); break; case D3DCMP_LESSEQUAL: renderer->setDepthCompare(sw::DEPTH_LESSEQUAL); break; case D3DCMP_GREATER: renderer->setDepthCompare(sw::DEPTH_GREATER); break; case D3DCMP_NOTEQUAL: renderer->setDepthCompare(sw::DEPTH_NOTEQUAL); break; case D3DCMP_GREATEREQUAL: renderer->setDepthCompare(sw::DEPTH_GREATEREQUAL); break; case D3DCMP_ALWAYS: renderer->setDepthCompare(sw::DEPTH_ALWAYS); break; default: ASSERT(false); } break; case D3DRS_ALPHAREF: renderer->setAlphaReference(value & 0x000000FF); break; case D3DRS_ALPHAFUNC: switch(value) { case D3DCMP_NEVER: renderer->setAlphaCompare(sw::ALPHA_NEVER); break; case D3DCMP_LESS: renderer->setAlphaCompare(sw::ALPHA_LESS); break; case D3DCMP_EQUAL: renderer->setAlphaCompare(sw::ALPHA_EQUAL); break; case D3DCMP_LESSEQUAL: renderer->setAlphaCompare(sw::ALPHA_LESSEQUAL); break; case D3DCMP_GREATER: renderer->setAlphaCompare(sw::ALPHA_GREATER); break; case D3DCMP_NOTEQUAL: renderer->setAlphaCompare(sw::ALPHA_NOTEQUAL); break; case D3DCMP_GREATEREQUAL: renderer->setAlphaCompare(sw::ALPHA_GREATEREQUAL); break; case D3DCMP_ALWAYS: renderer->setAlphaCompare(sw::ALPHA_ALWAYS); break; default: ASSERT(false); } break; case D3DRS_DITHERENABLE: // if(!init) UNIMPLEMENTED(); break; case D3DRS_ALPHABLENDENABLE: renderer->setAlphaBlendEnable(value != FALSE); break; case D3DRS_FOGENABLE: renderer->setFogEnable(value != FALSE); break; case D3DRS_FOGCOLOR: renderer->setFogColor(value); break; case D3DRS_FOGTABLEMODE: switch(value) { case D3DFOG_NONE: renderer->setPixelFogMode(sw::FOG_NONE); break; case D3DFOG_LINEAR: renderer->setPixelFogMode(sw::FOG_LINEAR); break; case D3DFOG_EXP: renderer->setPixelFogMode(sw::FOG_EXP); break; case D3DFOG_EXP2: renderer->setPixelFogMode(sw::FOG_EXP2); break; default: ASSERT(false); } break; case D3DRS_FOGSTART: renderer->setFogStart((float&)value); break; case D3DRS_FOGEND: renderer->setFogEnd((float&)value); break; case D3DRS_FOGDENSITY: renderer->setFogDensity((float&)value); break; case D3DRS_RANGEFOGENABLE: renderer->setRangeFogEnable(value != FALSE); break; case D3DRS_SPECULARENABLE: renderer->setSpecularEnable(value != FALSE); break; case D3DRS_STENCILENABLE: renderer->setStencilEnable(value != FALSE); break; case D3DRS_STENCILFAIL: switch(value) { case D3DSTENCILOP_KEEP: renderer->setStencilFailOperation(sw::OPERATION_KEEP); break; case D3DSTENCILOP_ZERO: renderer->setStencilFailOperation(sw::OPERATION_ZERO); break; case D3DSTENCILOP_REPLACE: renderer->setStencilFailOperation(sw::OPERATION_REPLACE); break; case D3DSTENCILOP_INCRSAT: renderer->setStencilFailOperation(sw::OPERATION_INCRSAT); break; case D3DSTENCILOP_DECRSAT: renderer->setStencilFailOperation(sw::OPERATION_DECRSAT); break; case D3DSTENCILOP_INVERT: renderer->setStencilFailOperation(sw::OPERATION_INVERT); break; case D3DSTENCILOP_INCR: renderer->setStencilFailOperation(sw::OPERATION_INCR); break; case D3DSTENCILOP_DECR: renderer->setStencilFailOperation(sw::OPERATION_DECR); break; default: ASSERT(false); } break; case D3DRS_STENCILZFAIL: switch(value) { case D3DSTENCILOP_KEEP: renderer->setStencilZFailOperation(sw::OPERATION_KEEP); break; case D3DSTENCILOP_ZERO: renderer->setStencilZFailOperation(sw::OPERATION_ZERO); break; case D3DSTENCILOP_REPLACE: renderer->setStencilZFailOperation(sw::OPERATION_REPLACE); break; case D3DSTENCILOP_INCRSAT: renderer->setStencilZFailOperation(sw::OPERATION_INCRSAT); break; case D3DSTENCILOP_DECRSAT: renderer->setStencilZFailOperation(sw::OPERATION_DECRSAT); break; case D3DSTENCILOP_INVERT: renderer->setStencilZFailOperation(sw::OPERATION_INVERT); break; case D3DSTENCILOP_INCR: renderer->setStencilZFailOperation(sw::OPERATION_INCR); break; case D3DSTENCILOP_DECR: renderer->setStencilZFailOperation(sw::OPERATION_DECR); break; default: ASSERT(false); } break; case D3DRS_STENCILPASS: switch(value) { case D3DSTENCILOP_KEEP: renderer->setStencilPassOperation(sw::OPERATION_KEEP); break; case D3DSTENCILOP_ZERO: renderer->setStencilPassOperation(sw::OPERATION_ZERO); break; case D3DSTENCILOP_REPLACE: renderer->setStencilPassOperation(sw::OPERATION_REPLACE); break; case D3DSTENCILOP_INCRSAT: renderer->setStencilPassOperation(sw::OPERATION_INCRSAT); break; case D3DSTENCILOP_DECRSAT: renderer->setStencilPassOperation(sw::OPERATION_DECRSAT); break; case D3DSTENCILOP_INVERT: renderer->setStencilPassOperation(sw::OPERATION_INVERT); break; case D3DSTENCILOP_INCR: renderer->setStencilPassOperation(sw::OPERATION_INCR); break; case D3DSTENCILOP_DECR: renderer->setStencilPassOperation(sw::OPERATION_DECR); break; default: ASSERT(false); } break; case D3DRS_STENCILFUNC: switch(value) { case D3DCMP_NEVER: renderer->setStencilCompare(sw::STENCIL_NEVER); break; case D3DCMP_LESS: renderer->setStencilCompare(sw::STENCIL_LESS); break; case D3DCMP_EQUAL: renderer->setStencilCompare(sw::STENCIL_EQUAL); break; case D3DCMP_LESSEQUAL: renderer->setStencilCompare(sw::STENCIL_LESSEQUAL); break; case D3DCMP_GREATER: renderer->setStencilCompare(sw::STENCIL_GREATER); break; case D3DCMP_NOTEQUAL: renderer->setStencilCompare(sw::STENCIL_NOTEQUAL); break; case D3DCMP_GREATEREQUAL: renderer->setStencilCompare(sw::STENCIL_GREATEREQUAL); break; case D3DCMP_ALWAYS: renderer->setStencilCompare(sw::STENCIL_ALWAYS); break; default: ASSERT(false); } break; case D3DRS_STENCILREF: renderer->setStencilReference(value); renderer->setStencilReferenceCCW(value); break; case D3DRS_STENCILMASK: renderer->setStencilMask(value); renderer->setStencilMaskCCW(value); break; case D3DRS_STENCILWRITEMASK: renderer->setStencilWriteMask(value); renderer->setStencilWriteMaskCCW(value); break; case D3DRS_TEXTUREFACTOR: renderer->setTextureFactor(value); break; case D3DRS_WRAP0: renderer->setTextureWrap(0, value); break; case D3DRS_WRAP1: renderer->setTextureWrap(1, value); break; case D3DRS_WRAP2: renderer->setTextureWrap(2, value); break; case D3DRS_WRAP3: renderer->setTextureWrap(3, value); break; case D3DRS_WRAP4: renderer->setTextureWrap(4, value); break; case D3DRS_WRAP5: renderer->setTextureWrap(5, value); break; case D3DRS_WRAP6: renderer->setTextureWrap(6, value); break; case D3DRS_WRAP7: renderer->setTextureWrap(7, value); break; case D3DRS_CLIPPING: // Ignored, clipping is always performed break; case D3DRS_LIGHTING: renderer->setLightingEnable(value != FALSE); break; case D3DRS_AMBIENT: renderer->setGlobalAmbient(value); break; case D3DRS_FOGVERTEXMODE: switch(value) { case D3DFOG_NONE: renderer->setVertexFogMode(sw::FOG_NONE); break; case D3DFOG_LINEAR: renderer->setVertexFogMode(sw::FOG_LINEAR); break; case D3DFOG_EXP: renderer->setVertexFogMode(sw::FOG_EXP); break; case D3DFOG_EXP2: renderer->setVertexFogMode(sw::FOG_EXP2); break; default: ASSERT(false); } break; case D3DRS_COLORVERTEX: renderer->setColorVertexEnable(value != FALSE); break; case D3DRS_LOCALVIEWER: renderer->setLocalViewer(value != FALSE); break; case D3DRS_NORMALIZENORMALS: renderer->setNormalizeNormals(value != FALSE); break; case D3DRS_DIFFUSEMATERIALSOURCE: switch(value) { case D3DMCS_MATERIAL: renderer->setDiffuseMaterialSource(sw::MATERIAL_MATERIAL); break; case D3DMCS_COLOR1: renderer->setDiffuseMaterialSource(sw::MATERIAL_COLOR1); break; case D3DMCS_COLOR2: renderer->setDiffuseMaterialSource(sw::MATERIAL_COLOR2); break; default: ASSERT(false); } break; case D3DRS_SPECULARMATERIALSOURCE: switch(value) { case D3DMCS_MATERIAL: renderer->setSpecularMaterialSource(sw::MATERIAL_MATERIAL); break; case D3DMCS_COLOR1: renderer->setSpecularMaterialSource(sw::MATERIAL_COLOR1); break; case D3DMCS_COLOR2: renderer->setSpecularMaterialSource(sw::MATERIAL_COLOR2); break; default: ASSERT(false); } break; case D3DRS_AMBIENTMATERIALSOURCE: switch(value) { case D3DMCS_MATERIAL: renderer->setAmbientMaterialSource(sw::MATERIAL_MATERIAL); break; case D3DMCS_COLOR1: renderer->setAmbientMaterialSource(sw::MATERIAL_COLOR1); break; case D3DMCS_COLOR2: renderer->setAmbientMaterialSource(sw::MATERIAL_COLOR2); break; default: ASSERT(false); } break; case D3DRS_EMISSIVEMATERIALSOURCE: switch(value) { case D3DMCS_MATERIAL: renderer->setEmissiveMaterialSource(sw::MATERIAL_MATERIAL); break; case D3DMCS_COLOR1: renderer->setEmissiveMaterialSource(sw::MATERIAL_COLOR1); break; case D3DMCS_COLOR2: renderer->setEmissiveMaterialSource(sw::MATERIAL_COLOR2); break; default: ASSERT(false); } break; case D3DRS_VERTEXBLEND: switch(value) { case D3DVBF_DISABLE: renderer->setVertexBlendMatrixCount(0); break; case D3DVBF_1WEIGHTS: renderer->setVertexBlendMatrixCount(2); break; case D3DVBF_2WEIGHTS: renderer->setVertexBlendMatrixCount(3); break; case D3DVBF_3WEIGHTS: renderer->setVertexBlendMatrixCount(4); break; case D3DVBF_TWEENING: UNIMPLEMENTED(); break; case D3DVBF_0WEIGHTS: renderer->setVertexBlendMatrixCount(1); break; default: ASSERT(false); } break; case D3DRS_CLIPPLANEENABLE: renderer->setClipFlags(value); break; case D3DRS_POINTSIZE: if(value == D3DFMT_INST && pixelShaderVersionX >= D3DPS_VERSION(2, 0)) // ATI hack to enable instancing on SM 2.0 hardware { instancingEnabled = true; } else if(value == D3DFMT_A2M1) // ATI hack to enable transparency anti-aliasing { renderer->setTransparencyAntialiasing(sw::TRANSPARENCY_ALPHA_TO_COVERAGE); renderer->setAlphaTestEnable(true); } else if(value == D3DFMT_A2M0) // ATI hack to disable transparency anti-aliasing { renderer->setTransparencyAntialiasing(sw::TRANSPARENCY_NONE); renderer->setAlphaTestEnable(false); } else { renderer->setPointSize((float&)value); } break; case D3DRS_POINTSIZE_MIN: renderer->setPointSizeMin((float&)value); break; case D3DRS_POINTSPRITEENABLE: renderer->setPointSpriteEnable(value != FALSE); break; case D3DRS_POINTSCALEENABLE: renderer->setPointScaleEnable(value != FALSE); break; case D3DRS_POINTSCALE_A: renderer->setPointScaleA((float&)value); break; case D3DRS_POINTSCALE_B: renderer->setPointScaleB((float&)value); break; case D3DRS_POINTSCALE_C: renderer->setPointScaleC((float&)value); break; case D3DRS_MULTISAMPLEANTIALIAS: // if(!init) UNIMPLEMENTED(); break; case D3DRS_MULTISAMPLEMASK: SetRenderTarget(0, renderTarget[0]); // Sets the multi-sample mask, if maskable break; case D3DRS_PATCHEDGESTYLE: if(!init) if(value != D3DPATCHEDGE_DISCRETE) UNIMPLEMENTED(); break; case D3DRS_DEBUGMONITORTOKEN: if(!init) UNIMPLEMENTED(); break; case D3DRS_POINTSIZE_MAX: renderer->setPointSizeMax((float&)value); break; case D3DRS_INDEXEDVERTEXBLENDENABLE: renderer->setIndexedVertexBlendEnable(value != FALSE); break; case D3DRS_COLORWRITEENABLE: renderer->setColorWriteMask(0, value & 0x0000000F); break; case D3DRS_TWEENFACTOR: if(!init) UNIMPLEMENTED(); break; case D3DRS_BLENDOP: switch(value) { case D3DBLENDOP_ADD: renderer->setBlendOperation(sw::BLENDOP_ADD); break; case D3DBLENDOP_SUBTRACT: renderer->setBlendOperation(sw::BLENDOP_SUB); break; case D3DBLENDOP_REVSUBTRACT: renderer->setBlendOperation(sw::BLENDOP_INVSUB); break; case D3DBLENDOP_MIN: renderer->setBlendOperation(sw::BLENDOP_MIN); break; case D3DBLENDOP_MAX: renderer->setBlendOperation(sw::BLENDOP_MAX); break; default: ASSERT(false); } break; case D3DRS_POSITIONDEGREE: if(!init) UNIMPLEMENTED(); break; case D3DRS_NORMALDEGREE: if(!init) UNIMPLEMENTED(); break; case D3DRS_SCISSORTESTENABLE: scissorEnable = (value != FALSE); break; case D3DRS_SLOPESCALEDEPTHBIAS: renderer->setSlopeDepthBias((float&)value); break; case D3DRS_ANTIALIASEDLINEENABLE: if(!init) if(value != FALSE) UNIMPLEMENTED(); break; case D3DRS_MINTESSELLATIONLEVEL: if(!init) UNIMPLEMENTED(); break; case D3DRS_MAXTESSELLATIONLEVEL: if(!init) UNIMPLEMENTED(); break; case D3DRS_ADAPTIVETESS_X: if(!init) if((float&)value != 0.0f) UNIMPLEMENTED(); break; case D3DRS_ADAPTIVETESS_Y: if(value == D3DFMT_ATOC) // NVIDIA hack to enable transparency anti-aliasing { renderer->setTransparencyAntialiasing(sw::TRANSPARENCY_ALPHA_TO_COVERAGE); } else if(value == D3DFMT_UNKNOWN) // NVIDIA hack to disable transparency anti-aliasing { renderer->setTransparencyAntialiasing(sw::TRANSPARENCY_NONE); } else { if(!init) if((float&)value != 0.0f) UNIMPLEMENTED(); } break; case D3DRS_ADAPTIVETESS_Z: if(!init) if((float&)value != 1.0f) UNIMPLEMENTED(); break; case D3DRS_ADAPTIVETESS_W: if(!init) if((float&)value != 0.0f) UNIMPLEMENTED(); break; case D3DRS_ENABLEADAPTIVETESSELLATION: if(!init) UNIMPLEMENTED(); break; case D3DRS_TWOSIDEDSTENCILMODE: renderer->setTwoSidedStencil(value != FALSE); break; case D3DRS_CCW_STENCILFAIL: switch(value) { case D3DSTENCILOP_KEEP: renderer->setStencilFailOperationCCW(sw::OPERATION_KEEP); break; case D3DSTENCILOP_ZERO: renderer->setStencilFailOperationCCW(sw::OPERATION_ZERO); break; case D3DSTENCILOP_REPLACE: renderer->setStencilFailOperationCCW(sw::OPERATION_REPLACE); break; case D3DSTENCILOP_INCRSAT: renderer->setStencilFailOperationCCW(sw::OPERATION_INCRSAT); break; case D3DSTENCILOP_DECRSAT: renderer->setStencilFailOperationCCW(sw::OPERATION_DECRSAT); break; case D3DSTENCILOP_INVERT: renderer->setStencilFailOperationCCW(sw::OPERATION_INVERT); break; case D3DSTENCILOP_INCR: renderer->setStencilFailOperationCCW(sw::OPERATION_INCR); break; case D3DSTENCILOP_DECR: renderer->setStencilFailOperationCCW(sw::OPERATION_DECR); break; default: ASSERT(false); } break; case D3DRS_CCW_STENCILZFAIL: switch(value) { case D3DSTENCILOP_KEEP: renderer->setStencilZFailOperationCCW(sw::OPERATION_KEEP); break; case D3DSTENCILOP_ZERO: renderer->setStencilZFailOperationCCW(sw::OPERATION_ZERO); break; case D3DSTENCILOP_REPLACE: renderer->setStencilZFailOperationCCW(sw::OPERATION_REPLACE); break; case D3DSTENCILOP_INCRSAT: renderer->setStencilZFailOperationCCW(sw::OPERATION_INCRSAT); break; case D3DSTENCILOP_DECRSAT: renderer->setStencilZFailOperationCCW(sw::OPERATION_DECRSAT); break; case D3DSTENCILOP_INVERT: renderer->setStencilZFailOperationCCW(sw::OPERATION_INVERT); break; case D3DSTENCILOP_INCR: renderer->setStencilZFailOperationCCW(sw::OPERATION_INCR); break; case D3DSTENCILOP_DECR: renderer->setStencilZFailOperationCCW(sw::OPERATION_DECR); break; default: ASSERT(false); } break; case D3DRS_CCW_STENCILPASS: switch(value) { case D3DSTENCILOP_KEEP: renderer->setStencilPassOperationCCW(sw::OPERATION_KEEP); break; case D3DSTENCILOP_ZERO: renderer->setStencilPassOperationCCW(sw::OPERATION_ZERO); break; case D3DSTENCILOP_REPLACE: renderer->setStencilPassOperationCCW(sw::OPERATION_REPLACE); break; case D3DSTENCILOP_INCRSAT: renderer->setStencilPassOperationCCW(sw::OPERATION_INCRSAT); break; case D3DSTENCILOP_DECRSAT: renderer->setStencilPassOperationCCW(sw::OPERATION_DECRSAT); break; case D3DSTENCILOP_INVERT: renderer->setStencilPassOperationCCW(sw::OPERATION_INVERT); break; case D3DSTENCILOP_INCR: renderer->setStencilPassOperationCCW(sw::OPERATION_INCR); break; case D3DSTENCILOP_DECR: renderer->setStencilPassOperationCCW(sw::OPERATION_DECR); break; default: ASSERT(false); } break; case D3DRS_CCW_STENCILFUNC: switch(value) { case D3DCMP_NEVER: renderer->setStencilCompareCCW(sw::STENCIL_NEVER); break; case D3DCMP_LESS: renderer->setStencilCompareCCW(sw::STENCIL_LESS); break; case D3DCMP_EQUAL: renderer->setStencilCompareCCW(sw::STENCIL_EQUAL); break; case D3DCMP_LESSEQUAL: renderer->setStencilCompareCCW(sw::STENCIL_LESSEQUAL); break; case D3DCMP_GREATER: renderer->setStencilCompareCCW(sw::STENCIL_GREATER); break; case D3DCMP_NOTEQUAL: renderer->setStencilCompareCCW(sw::STENCIL_NOTEQUAL); break; case D3DCMP_GREATEREQUAL: renderer->setStencilCompareCCW(sw::STENCIL_GREATEREQUAL); break; case D3DCMP_ALWAYS: renderer->setStencilCompareCCW(sw::STENCIL_ALWAYS); break; default: ASSERT(false); } break; case D3DRS_COLORWRITEENABLE1: renderer->setColorWriteMask(1, value); break; case D3DRS_COLORWRITEENABLE2: renderer->setColorWriteMask(2, value); break; case D3DRS_COLORWRITEENABLE3: renderer->setColorWriteMask(3, value); break; case D3DRS_BLENDFACTOR: renderer->setBlendConstant(sw::Color<float>(value)); break; case D3DRS_SRGBWRITEENABLE: renderer->setWriteSRGB(value != FALSE); break; case D3DRS_DEPTHBIAS: renderer->setDepthBias((float&)value); break; case D3DRS_WRAP8: renderer->setTextureWrap(8, value); break; case D3DRS_WRAP9: renderer->setTextureWrap(9, value); break; case D3DRS_WRAP10: renderer->setTextureWrap(10, value); break; case D3DRS_WRAP11: renderer->setTextureWrap(11, value); break; case D3DRS_WRAP12: renderer->setTextureWrap(12, value); break; case D3DRS_WRAP13: renderer->setTextureWrap(13, value); break; case D3DRS_WRAP14: renderer->setTextureWrap(14, value); break; case D3DRS_WRAP15: renderer->setTextureWrap(15, value); break; case D3DRS_SEPARATEALPHABLENDENABLE: renderer->setSeparateAlphaBlendEnable(value != FALSE); break; case D3DRS_SRCBLENDALPHA: switch(value) { case D3DBLEND_ZERO: renderer->setSourceBlendFactorAlpha(sw::BLEND_ZERO); break; case D3DBLEND_ONE: renderer->setSourceBlendFactorAlpha(sw::BLEND_ONE); break; case D3DBLEND_SRCCOLOR: renderer->setSourceBlendFactorAlpha(sw::BLEND_SOURCE); break; case D3DBLEND_INVSRCCOLOR: renderer->setSourceBlendFactorAlpha(sw::BLEND_INVSOURCE); break; case D3DBLEND_SRCALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_INVSRCALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_DESTALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_DESTALPHA); break; case D3DBLEND_INVDESTALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_INVDESTALPHA); break; case D3DBLEND_DESTCOLOR: renderer->setSourceBlendFactorAlpha(sw::BLEND_DEST); break; case D3DBLEND_INVDESTCOLOR: renderer->setSourceBlendFactorAlpha(sw::BLEND_INVDEST); break; case D3DBLEND_SRCALPHASAT: renderer->setSourceBlendFactorAlpha(sw::BLEND_SRCALPHASAT); break; case D3DBLEND_BOTHSRCALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_SOURCEALPHA); renderer->setDestBlendFactorAlpha(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_BOTHINVSRCALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_INVSOURCEALPHA); renderer->setDestBlendFactorAlpha(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_BLENDFACTOR: renderer->setSourceBlendFactorAlpha(sw::BLEND_CONSTANT); break; case D3DBLEND_INVBLENDFACTOR: renderer->setSourceBlendFactorAlpha(sw::BLEND_INVCONSTANT); break; default: ASSERT(false); } break; case D3DRS_DESTBLENDALPHA: switch(value) { case D3DBLEND_ZERO: renderer->setDestBlendFactorAlpha(sw::BLEND_ZERO); break; case D3DBLEND_ONE: renderer->setDestBlendFactorAlpha(sw::BLEND_ONE); break; case D3DBLEND_SRCCOLOR: renderer->setDestBlendFactorAlpha(sw::BLEND_SOURCE); break; case D3DBLEND_INVSRCCOLOR: renderer->setDestBlendFactorAlpha(sw::BLEND_INVSOURCE); break; case D3DBLEND_SRCALPHA: renderer->setDestBlendFactorAlpha(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_INVSRCALPHA: renderer->setDestBlendFactorAlpha(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_DESTALPHA: renderer->setDestBlendFactorAlpha(sw::BLEND_DESTALPHA); break; case D3DBLEND_INVDESTALPHA: renderer->setDestBlendFactorAlpha(sw::BLEND_INVDESTALPHA); break; case D3DBLEND_DESTCOLOR: renderer->setDestBlendFactorAlpha(sw::BLEND_DEST); break; case D3DBLEND_INVDESTCOLOR: renderer->setDestBlendFactorAlpha(sw::BLEND_INVDEST); break; case D3DBLEND_SRCALPHASAT: renderer->setDestBlendFactorAlpha(sw::BLEND_SRCALPHASAT); break; case D3DBLEND_BOTHSRCALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_SOURCEALPHA); renderer->setDestBlendFactorAlpha(sw::BLEND_INVSOURCEALPHA); break; case D3DBLEND_BOTHINVSRCALPHA: renderer->setSourceBlendFactorAlpha(sw::BLEND_INVSOURCEALPHA); renderer->setDestBlendFactorAlpha(sw::BLEND_SOURCEALPHA); break; case D3DBLEND_BLENDFACTOR: renderer->setDestBlendFactorAlpha(sw::BLEND_CONSTANT); break; case D3DBLEND_INVBLENDFACTOR: renderer->setDestBlendFactorAlpha(sw::BLEND_INVCONSTANT); break; default: ASSERT(false); } break; case D3DRS_BLENDOPALPHA: switch(value) { case D3DBLENDOP_ADD: renderer->setBlendOperationAlpha(sw::BLENDOP_ADD); break; case D3DBLENDOP_SUBTRACT: renderer->setBlendOperationAlpha(sw::BLENDOP_SUB); break; case D3DBLENDOP_REVSUBTRACT: renderer->setBlendOperationAlpha(sw::BLENDOP_INVSUB); break; case D3DBLENDOP_MIN: renderer->setBlendOperationAlpha(sw::BLENDOP_MIN); break; case D3DBLENDOP_MAX: renderer->setBlendOperationAlpha(sw::BLENDOP_MAX); break; default: ASSERT(false); } break; default: ASSERT(false); } } else // stateRecorder { stateRecorder->setRenderState(state, value); } return D3D_OK; } long Direct3DDevice9::SetRenderTarget(unsigned long index, IDirect3DSurface9 *iRenderTarget) { CriticalSection cs(this); TRACE("unsigned long index = %d, IDirect3DSurface9 *newRenderTarget = 0x%0.8p", index, iRenderTarget); // FIXME: Check for D3DUSAGE_RENDERTARGET if(index >= 4 || (index == 0 && !iRenderTarget)) { return INVALIDCALL(); } Direct3DSurface9 *renderTarget = static_cast<Direct3DSurface9*>(iRenderTarget); if(renderTarget) { renderTarget->bind(); } if(this->renderTarget[index]) { this->renderTarget[index]->unbind(); } this->renderTarget[index] = renderTarget; if(renderTarget && index == 0) { D3DSURFACE_DESC renderTargetDesc; renderTarget->GetDesc(&renderTargetDesc); // Reset viewport to size of current render target viewport.X = 0; viewport.Y = 0; viewport.Width = renderTargetDesc.Width; viewport.Height = renderTargetDesc.Height; viewport.MinZ = 0; viewport.MaxZ = 1; // Reset scissor rectangle to size of current render target scissorRect.left = 0; scissorRect.top = 0; scissorRect.right = renderTargetDesc.Width; scissorRect.bottom = renderTargetDesc.Height; // Set the multi-sample mask, if maskable if(renderTargetDesc.MultiSampleType != D3DMULTISAMPLE_NONE && renderTargetDesc.MultiSampleType != D3DMULTISAMPLE_NONMASKABLE) { renderer->setMultiSampleMask(renderState[D3DRS_MULTISAMPLEMASK]); } else { renderer->setMultiSampleMask(0xFFFFFFFF); } } renderer->setRenderTarget(index, renderTarget); return D3D_OK; } long Direct3DDevice9::SetSamplerState(unsigned long sampler, D3DSAMPLERSTATETYPE state, unsigned long value) { CriticalSection cs(this); TRACE("unsigned long sampler = %d, D3DSAMPLERSTATETYPE state = %d, unsigned long value = %d", sampler, state, value); if(state < D3DSAMP_ADDRESSU || state > D3DSAMP_DMAPOFFSET) { return INVALIDCALL(); } if((sampler >= 16 && sampler <= D3DDMAPSAMPLER) || sampler > D3DVERTEXTEXTURESAMPLER3) { return INVALIDCALL(); } if(sampler >= D3DVERTEXTEXTURESAMPLER0) { sampler = 16 + (sampler - D3DVERTEXTEXTURESAMPLER0); } if(!stateRecorder) { if(!init && samplerState[sampler][state] == value) { return D3D_OK; } samplerState[sampler][state] = value; sw::SamplerType type = sampler < 16 ? sw::SAMPLER_PIXEL : sw::SAMPLER_VERTEX; int index = sampler < 16 ? sampler : sampler - 16; // Sampler index within type group switch(state) { case D3DSAMP_ADDRESSU: switch(value) { case D3DTADDRESS_WRAP: renderer->setAddressingModeU(type, index, sw::ADDRESSING_WRAP); break; case D3DTADDRESS_MIRROR: renderer->setAddressingModeU(type, index, sw::ADDRESSING_MIRROR); break; case D3DTADDRESS_CLAMP: renderer->setAddressingModeU(type, index, sw::ADDRESSING_CLAMP); break; case D3DTADDRESS_BORDER: renderer->setAddressingModeU(type, index, sw::ADDRESSING_BORDER); break; case D3DTADDRESS_MIRRORONCE: renderer->setAddressingModeU(type, index, sw::ADDRESSING_MIRRORONCE); break; default: ASSERT(false); } break; case D3DSAMP_ADDRESSV: switch(value) { case D3DTADDRESS_WRAP: renderer->setAddressingModeV(type, index, sw::ADDRESSING_WRAP); break; case D3DTADDRESS_MIRROR: renderer->setAddressingModeV(type, index, sw::ADDRESSING_MIRROR); break; case D3DTADDRESS_CLAMP: renderer->setAddressingModeV(type, index, sw::ADDRESSING_CLAMP); break; case D3DTADDRESS_BORDER: renderer->setAddressingModeV(type, index, sw::ADDRESSING_BORDER); break; case D3DTADDRESS_MIRRORONCE: renderer->setAddressingModeV(type, index, sw::ADDRESSING_MIRRORONCE); break; default: ASSERT(false); } break; case D3DSAMP_ADDRESSW: switch(value) { case D3DTADDRESS_WRAP: renderer->setAddressingModeW(type, index, sw::ADDRESSING_WRAP); break; case D3DTADDRESS_MIRROR: renderer->setAddressingModeW(type, index, sw::ADDRESSING_MIRROR); break; case D3DTADDRESS_CLAMP: renderer->setAddressingModeW(type, index, sw::ADDRESSING_CLAMP); break; case D3DTADDRESS_BORDER: renderer->setAddressingModeW(type, index, sw::ADDRESSING_BORDER); break; case D3DTADDRESS_MIRRORONCE: renderer->setAddressingModeW(type, index, sw::ADDRESSING_MIRRORONCE); break; default: ASSERT(false); } break; case D3DSAMP_BORDERCOLOR: renderer->setBorderColor(type, index, value); break; case D3DSAMP_MAGFILTER: // NOTE: SwiftShader does not differentiate between minification and magnification filter switch(value) { case D3DTEXF_NONE: renderer->setTextureFilter(type, index, sw::FILTER_POINT); // FIXME: Only for mipmap filter break; case D3DTEXF_POINT: renderer->setTextureFilter(type, index, sw::FILTER_POINT); break; case D3DTEXF_LINEAR: renderer->setTextureFilter(type, index, sw::FILTER_LINEAR); break; case D3DTEXF_ANISOTROPIC: renderer->setTextureFilter(type, index, sw::FILTER_ANISOTROPIC); break; case D3DTEXF_PYRAMIDALQUAD: renderer->setTextureFilter(type, index, sw::FILTER_LINEAR); // FIXME: Unimplemented, fail silently break; case D3DTEXF_GAUSSIANQUAD: renderer->setTextureFilter(type, index, sw::FILTER_LINEAR); // FIXME: Unimplemented, fail silently break; default: return INVALIDCALL(); }; break; case D3DSAMP_MINFILTER: // NOTE: SwiftShader does not differentiate between minification and magnification filter switch(value) { case D3DTEXF_NONE: renderer->setTextureFilter(type, index, sw::FILTER_POINT); // FIXME: Only for mipmap filter break; case D3DTEXF_POINT: renderer->setTextureFilter(type, index, sw::FILTER_POINT); break; case D3DTEXF_LINEAR: renderer->setTextureFilter(type, index, sw::FILTER_LINEAR); break; case D3DTEXF_ANISOTROPIC: renderer->setTextureFilter(type, index, sw::FILTER_ANISOTROPIC); break; case D3DTEXF_PYRAMIDALQUAD: renderer->setTextureFilter(type, index, sw::FILTER_LINEAR); // FIXME: Unimplemented, fail silently break; case D3DTEXF_GAUSSIANQUAD: renderer->setTextureFilter(type, index, sw::FILTER_LINEAR); // FIXME: Unimplemented, fail silently break; default: return INVALIDCALL(); }; break; case D3DSAMP_MIPFILTER: switch(value) { case D3DTEXF_NONE: renderer->setMipmapFilter(type, index, sw::MIPMAP_NONE); break; case D3DTEXF_POINT: renderer->setMipmapFilter(type, index, sw::MIPMAP_POINT); break; case D3DTEXF_LINEAR: renderer->setMipmapFilter(type, index, sw::MIPMAP_LINEAR); break; case D3DTEXF_ANISOTROPIC: renderer->setMipmapFilter(type, index, sw::MIPMAP_LINEAR); // FIXME: Only for texture filter break; case D3DTEXF_PYRAMIDALQUAD: renderer->setMipmapFilter(type, index, sw::MIPMAP_LINEAR); // FIXME: Only for texture filter break; case D3DTEXF_GAUSSIANQUAD: renderer->setMipmapFilter(type, index, sw::MIPMAP_LINEAR); // FIXME: Only for texture filter break; default: return INVALIDCALL(); }; break; case D3DSAMP_MIPMAPLODBIAS: if(value == D3DFMT_GET4) // ATI hack to enable Fetch4 { renderer->setGatherEnable(type, index, true); } else if(value == D3DFMT_GET1) // ATI hack to disable Fetch4 { renderer->setGatherEnable(type, index, false); } else { float LOD = (float&)value - sw::log2((float)context->renderTarget[0]->getSuperSampleCount()); // FIXME: Update when render target changes renderer->setMipmapLOD(type, index, LOD); } break; case D3DSAMP_MAXMIPLEVEL: break; case D3DSAMP_MAXANISOTROPY: renderer->setMaxAnisotropy(type, index, sw::clamp((unsigned int)value, (unsigned int)1, maxAnisotropy)); break; case D3DSAMP_SRGBTEXTURE: renderer->setReadSRGB(type, index, value != FALSE); break; case D3DSAMP_ELEMENTINDEX: if(!init) UNIMPLEMENTED(); // Multi-element textures deprecated in favor of multiple render targets break; case D3DSAMP_DMAPOFFSET: // if(!init) UNIMPLEMENTED(); break; default: ASSERT(false); } } else // stateRecorder { stateRecorder->setSamplerState(sampler, state, value); } return D3D_OK; } long Direct3DDevice9::SetScissorRect(const RECT *rect) { CriticalSection cs(this); TRACE("const RECT *rect = 0x%0.8p", rect); if(!rect) { return INVALIDCALL(); } if(!stateRecorder) { scissorRect = *rect; } else { stateRecorder->setScissorRect(rect); } return D3D_OK; } long Direct3DDevice9::SetSoftwareVertexProcessing(int software) { CriticalSection cs(this); TRACE("int software = %d", software); if(behaviourFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING && software == FALSE) { return INVALIDCALL(); } if(behaviourFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING && software == TRUE) { return INVALIDCALL(); } softwareVertexProcessing = (software != FALSE); return D3D_OK; } long Direct3DDevice9::SetStreamSource(unsigned int stream, IDirect3DVertexBuffer9 *iVertexBuffer, unsigned int offset, unsigned int stride) { CriticalSection cs(this); TRACE("unsigned int stream = %d, IDirect3DVertexBuffer9 *data = 0x%0.8p, unsigned int offset = %d, unsigned int stride = %d", stream, iVertexBuffer, offset, stride); Direct3DVertexBuffer9 *vertexBuffer = static_cast<Direct3DVertexBuffer9*>(iVertexBuffer); if(!stateRecorder) { if(dataStream[stream] == vertexBuffer && streamOffset[stream] == offset && streamStride[stream] == stride) { return D3D_OK; } if(vertexBuffer) { vertexBuffer->bind(); } if(dataStream[stream]) { dataStream[stream]->unbind(); } dataStream[stream] = vertexBuffer; streamOffset[stream] = offset; streamStride[stream] = stride; } else { stateRecorder->setStreamSource(stream, vertexBuffer, offset, stride); } return D3D_OK; } long Direct3DDevice9::SetStreamSourceFreq(unsigned int streamNumber, unsigned int divider) { CriticalSection cs(this); TRACE("unsigned int streamNumber = %d, unsigned int divider = %d", streamNumber, divider); if(!instancingEnabled) { return INVALIDCALL(); } if(!stateRecorder) { streamSourceFreq[streamNumber] = divider; } else { stateRecorder->setStreamSourceFreq(streamNumber, divider); } return D3D_OK; } long Direct3DDevice9::SetTexture(unsigned long sampler, IDirect3DBaseTexture9 *iBaseTexture) { CriticalSection cs(this); TRACE("unsigned long sampler = %d, IDirect3DBaseTexture9 *texture = 0x%0.8p", sampler, iBaseTexture); if((sampler >= 16 && sampler <= D3DDMAPSAMPLER) || sampler > D3DVERTEXTEXTURESAMPLER3) { return INVALIDCALL(); } if(sampler >= D3DVERTEXTEXTURESAMPLER0) { sampler = 16 + (sampler - D3DVERTEXTEXTURESAMPLER0); } Direct3DBaseTexture9 *baseTexture = dynamic_cast<Direct3DBaseTexture9*>(iBaseTexture); if(!stateRecorder) { if(texture[sampler] == baseTexture) { return D3D_OK; } if(baseTexture) { baseTexture->bind(); // FIXME: Bind individual sub-surfaces? } if(texture[sampler]) { texture[sampler]->unbind(); } texture[sampler] = baseTexture; } else { stateRecorder->setTexture(sampler, baseTexture); } return D3D_OK; } long Direct3DDevice9::SetTextureStageState(unsigned long stage, D3DTEXTURESTAGESTATETYPE type, unsigned long value) { CriticalSection cs(this); TRACE("unsigned long stage = %d, D3DTEXTURESTAGESTATETYPE type = %d, unsigned long value = %d", stage, type, value); if(stage < 0 || stage >= 8 || type < D3DTSS_COLOROP || type > D3DTSS_CONSTANT) { return INVALIDCALL(); } if(!stateRecorder) { if(!init && textureStageState[stage][type] == value) { return D3D_OK; } textureStageState[stage][type] = value; switch(type) { case D3DTSS_COLOROP: switch(value) { case D3DTOP_DISABLE: renderer->setStageOperation(stage, sw::TextureStage::STAGE_DISABLE); break; case D3DTOP_SELECTARG1: renderer->setStageOperation(stage, sw::TextureStage::STAGE_SELECTARG1); break; case D3DTOP_SELECTARG2: renderer->setStageOperation(stage, sw::TextureStage::STAGE_SELECTARG2); break; case D3DTOP_MODULATE: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MODULATE); break; case D3DTOP_MODULATE2X: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MODULATE2X); break; case D3DTOP_MODULATE4X: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MODULATE4X); break; case D3DTOP_ADD: renderer->setStageOperation(stage, sw::TextureStage::STAGE_ADD); break; case D3DTOP_ADDSIGNED: renderer->setStageOperation(stage, sw::TextureStage::STAGE_ADDSIGNED); break; case D3DTOP_ADDSIGNED2X: renderer->setStageOperation(stage, sw::TextureStage::STAGE_ADDSIGNED2X); break; case D3DTOP_SUBTRACT: renderer->setStageOperation(stage, sw::TextureStage::STAGE_SUBTRACT); break; case D3DTOP_ADDSMOOTH: renderer->setStageOperation(stage, sw::TextureStage::STAGE_ADDSMOOTH); break; case D3DTOP_BLENDDIFFUSEALPHA: renderer->setStageOperation(stage, sw::TextureStage::STAGE_BLENDDIFFUSEALPHA); break; case D3DTOP_BLENDTEXTUREALPHA: renderer->setStageOperation(stage, sw::TextureStage::STAGE_BLENDTEXTUREALPHA); break; case D3DTOP_BLENDFACTORALPHA: renderer->setStageOperation(stage, sw::TextureStage::STAGE_BLENDFACTORALPHA); break; case D3DTOP_BLENDTEXTUREALPHAPM: renderer->setStageOperation(stage, sw::TextureStage::STAGE_BLENDTEXTUREALPHAPM); break; case D3DTOP_BLENDCURRENTALPHA: renderer->setStageOperation(stage, sw::TextureStage::STAGE_BLENDCURRENTALPHA); break; case D3DTOP_PREMODULATE: renderer->setStageOperation(stage, sw::TextureStage::STAGE_PREMODULATE); break; case D3DTOP_MODULATEALPHA_ADDCOLOR: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MODULATEALPHA_ADDCOLOR); break; case D3DTOP_MODULATECOLOR_ADDALPHA: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MODULATECOLOR_ADDALPHA); break; case D3DTOP_MODULATEINVALPHA_ADDCOLOR: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MODULATEINVALPHA_ADDCOLOR); break; case D3DTOP_MODULATEINVCOLOR_ADDALPHA: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MODULATEINVCOLOR_ADDALPHA); break; case D3DTOP_BUMPENVMAP: renderer->setStageOperation(stage, sw::TextureStage::STAGE_BUMPENVMAP); break; case D3DTOP_BUMPENVMAPLUMINANCE: renderer->setStageOperation(stage, sw::TextureStage::STAGE_BUMPENVMAPLUMINANCE); break; case D3DTOP_DOTPRODUCT3: renderer->setStageOperation(stage, sw::TextureStage::STAGE_DOT3); break; case D3DTOP_MULTIPLYADD: renderer->setStageOperation(stage, sw::TextureStage::STAGE_MULTIPLYADD); break; case D3DTOP_LERP: renderer->setStageOperation(stage, sw::TextureStage::STAGE_LERP); break; default: ASSERT(false); } break; case D3DTSS_COLORARG1: switch(value & D3DTA_SELECTMASK) { case D3DTA_DIFFUSE: renderer->setFirstArgument(stage, sw::TextureStage::SOURCE_DIFFUSE); break; case D3DTA_CURRENT: renderer->setFirstArgument(stage, sw::TextureStage::SOURCE_CURRENT); break; case D3DTA_TEXTURE: renderer->setFirstArgument(stage, sw::TextureStage::SOURCE_TEXTURE); break; case D3DTA_TFACTOR: renderer->setFirstArgument(stage, sw::TextureStage::SOURCE_TFACTOR); break; case D3DTA_SPECULAR: renderer->setFirstArgument(stage, sw::TextureStage::SOURCE_SPECULAR); break; case D3DTA_TEMP: renderer->setFirstArgument(stage, sw::TextureStage::SOURCE_TEMP); break; case D3DTA_CONSTANT: renderer->setFirstArgument(stage, sw::TextureStage::SOURCE_CONSTANT); break; default: ASSERT(false); } switch(value & ~D3DTA_SELECTMASK) { case 0: renderer->setFirstModifier(stage, sw::TextureStage::MODIFIER_COLOR); break; case D3DTA_COMPLEMENT: renderer->setFirstModifier(stage, sw::TextureStage::MODIFIER_INVCOLOR); break; case D3DTA_ALPHAREPLICATE: renderer->setFirstModifier(stage, sw::TextureStage::MODIFIER_ALPHA); break; case D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE: renderer->setFirstModifier(stage, sw::TextureStage::MODIFIER_INVALPHA); break; default: ASSERT(false); } break; case D3DTSS_COLORARG2: switch(value & D3DTA_SELECTMASK) { case D3DTA_DIFFUSE: renderer->setSecondArgument(stage, sw::TextureStage::SOURCE_DIFFUSE); break; case D3DTA_CURRENT: renderer->setSecondArgument(stage, sw::TextureStage::SOURCE_CURRENT); break; case D3DTA_TEXTURE: renderer->setSecondArgument(stage, sw::TextureStage::SOURCE_TEXTURE); break; case D3DTA_TFACTOR: renderer->setSecondArgument(stage, sw::TextureStage::SOURCE_TFACTOR); break; case D3DTA_SPECULAR: renderer->setSecondArgument(stage, sw::TextureStage::SOURCE_SPECULAR); break; case D3DTA_TEMP: renderer->setSecondArgument(stage, sw::TextureStage::SOURCE_TEMP); break; case D3DTA_CONSTANT: renderer->setSecondArgument(stage, sw::TextureStage::SOURCE_CONSTANT); break; default: ASSERT(false); } switch(value & ~D3DTA_SELECTMASK) { case 0: renderer->setSecondModifier(stage, sw::TextureStage::MODIFIER_COLOR); break; case D3DTA_COMPLEMENT: renderer->setSecondModifier(stage, sw::TextureStage::MODIFIER_INVCOLOR); break; case D3DTA_ALPHAREPLICATE: renderer->setSecondModifier(stage, sw::TextureStage::MODIFIER_ALPHA); break; case D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE: renderer->setSecondModifier(stage, sw::TextureStage::MODIFIER_INVALPHA); break; default: ASSERT(false); } break; case D3DTSS_ALPHAOP: switch(value) { case D3DTOP_DISABLE: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_DISABLE); break; case D3DTOP_SELECTARG1: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_SELECTARG1); break; case D3DTOP_SELECTARG2: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_SELECTARG2); break; case D3DTOP_MODULATE: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MODULATE); break; case D3DTOP_MODULATE2X: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MODULATE2X); break; case D3DTOP_MODULATE4X: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MODULATE4X); break; case D3DTOP_ADD: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_ADD); break; case D3DTOP_ADDSIGNED: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_ADDSIGNED); break; case D3DTOP_ADDSIGNED2X: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_ADDSIGNED2X); break; case D3DTOP_SUBTRACT: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_SUBTRACT); break; case D3DTOP_ADDSMOOTH: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_ADDSMOOTH); break; case D3DTOP_BLENDDIFFUSEALPHA: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_BLENDDIFFUSEALPHA); break; case D3DTOP_BLENDTEXTUREALPHA: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_BLENDTEXTUREALPHA); break; case D3DTOP_BLENDFACTORALPHA: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_BLENDFACTORALPHA); break; case D3DTOP_BLENDTEXTUREALPHAPM: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_BLENDTEXTUREALPHAPM); break; case D3DTOP_BLENDCURRENTALPHA: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_BLENDCURRENTALPHA); break; case D3DTOP_PREMODULATE: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_PREMODULATE); break; case D3DTOP_MODULATEALPHA_ADDCOLOR: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MODULATEALPHA_ADDCOLOR); break; case D3DTOP_MODULATECOLOR_ADDALPHA: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MODULATECOLOR_ADDALPHA); break; case D3DTOP_MODULATEINVALPHA_ADDCOLOR: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MODULATEINVALPHA_ADDCOLOR); break; case D3DTOP_MODULATEINVCOLOR_ADDALPHA: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MODULATEINVCOLOR_ADDALPHA); break; case D3DTOP_BUMPENVMAP: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_BUMPENVMAP); break; case D3DTOP_BUMPENVMAPLUMINANCE: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_BUMPENVMAPLUMINANCE); break; case D3DTOP_DOTPRODUCT3: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_DOT3); break; case D3DTOP_MULTIPLYADD: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_MULTIPLYADD); break; case D3DTOP_LERP: renderer->setStageOperationAlpha(stage, sw::TextureStage::STAGE_LERP); break; default: ASSERT(false); } break; case D3DTSS_ALPHAARG1: switch(value & D3DTA_SELECTMASK) { case D3DTA_DIFFUSE: renderer->setFirstArgumentAlpha(stage, sw::TextureStage::SOURCE_DIFFUSE); break; case D3DTA_CURRENT: renderer->setFirstArgumentAlpha(stage, sw::TextureStage::SOURCE_CURRENT); break; case D3DTA_TEXTURE: renderer->setFirstArgumentAlpha(stage, sw::TextureStage::SOURCE_TEXTURE); break; case D3DTA_TFACTOR: renderer->setFirstArgumentAlpha(stage, sw::TextureStage::SOURCE_TFACTOR); break; case D3DTA_SPECULAR: renderer->setFirstArgumentAlpha(stage, sw::TextureStage::SOURCE_SPECULAR); break; case D3DTA_TEMP: renderer->setFirstArgumentAlpha(stage, sw::TextureStage::SOURCE_TEMP); break; case D3DTA_CONSTANT: renderer->setFirstArgumentAlpha(stage, sw::TextureStage::SOURCE_CONSTANT); break; default: ASSERT(false); } switch(value & ~D3DTA_SELECTMASK) { case 0: renderer->setFirstModifierAlpha(stage, sw::TextureStage::MODIFIER_COLOR); break; case D3DTA_COMPLEMENT: renderer->setFirstModifierAlpha(stage, sw::TextureStage::MODIFIER_INVCOLOR); break; case D3DTA_ALPHAREPLICATE: renderer->setFirstModifierAlpha(stage, sw::TextureStage::MODIFIER_ALPHA); break; case D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE: renderer->setSecondModifier(stage, sw::TextureStage::MODIFIER_INVALPHA); break; default: ASSERT(false); } break; case D3DTSS_ALPHAARG2: switch(value & D3DTA_SELECTMASK) { case D3DTA_DIFFUSE: renderer->setSecondArgumentAlpha(stage, sw::TextureStage::SOURCE_DIFFUSE); break; case D3DTA_CURRENT: renderer->setSecondArgumentAlpha(stage, sw::TextureStage::SOURCE_CURRENT); break; case D3DTA_TEXTURE: renderer->setSecondArgumentAlpha(stage, sw::TextureStage::SOURCE_TEXTURE); break; case D3DTA_TFACTOR: renderer->setSecondArgumentAlpha(stage, sw::TextureStage::SOURCE_TFACTOR); break; case D3DTA_SPECULAR: renderer->setSecondArgumentAlpha(stage, sw::TextureStage::SOURCE_SPECULAR); break; case D3DTA_TEMP: renderer->setSecondArgumentAlpha(stage, sw::TextureStage::SOURCE_TEMP); break; case D3DTA_CONSTANT: renderer->setSecondArgumentAlpha(stage, sw::TextureStage::SOURCE_CONSTANT); break; default: ASSERT(false); } switch(value & ~D3DTA_SELECTMASK) { case 0: renderer->setSecondModifierAlpha(stage, sw::TextureStage::MODIFIER_COLOR); break; case D3DTA_COMPLEMENT: renderer->setSecondModifierAlpha(stage, sw::TextureStage::MODIFIER_INVCOLOR); break; case D3DTA_ALPHAREPLICATE: renderer->setSecondModifierAlpha(stage, sw::TextureStage::MODIFIER_ALPHA); break; case D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE: renderer->setSecondModifierAlpha(stage, sw::TextureStage::MODIFIER_INVALPHA); break; default: ASSERT(false); } break; case D3DTSS_BUMPENVMAT00: renderer->setBumpmapMatrix(stage, 0, (float&)value); break; case D3DTSS_BUMPENVMAT01: renderer->setBumpmapMatrix(stage, 1, (float&)value); break; case D3DTSS_BUMPENVMAT10: renderer->setBumpmapMatrix(stage, 2, (float&)value); break; case D3DTSS_BUMPENVMAT11: renderer->setBumpmapMatrix(stage, 3, (float&)value); break; case D3DTSS_TEXCOORDINDEX: renderer->setTexCoordIndex(stage, value & 0x0000FFFF); switch(value & 0xFFFF0000) { case D3DTSS_TCI_PASSTHRU: renderer->setTexGen(stage, sw::TEXGEN_PASSTHRU); break; case D3DTSS_TCI_CAMERASPACENORMAL: renderer->setTexCoordIndex(stage, stage); renderer->setTexGen(stage, sw::TEXGEN_NORMAL); break; case D3DTSS_TCI_CAMERASPACEPOSITION: renderer->setTexCoordIndex(stage, stage); renderer->setTexGen(stage, sw::TEXGEN_POSITION); break; case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: renderer->setTexCoordIndex(stage, stage); renderer->setTexGen(stage, sw::TEXGEN_REFLECTION); break; case D3DTSS_TCI_SPHEREMAP: renderer->setTexCoordIndex(stage, stage); renderer->setTexGen(stage, sw::TEXGEN_SPHEREMAP); break; default: ASSERT(false); } break; case D3DTSS_BUMPENVLSCALE: renderer->setLuminanceScale(stage, (float&)value); break; case D3DTSS_BUMPENVLOFFSET: renderer->setLuminanceOffset(stage, (float&)value); break; case D3DTSS_TEXTURETRANSFORMFLAGS: switch(value & ~D3DTTFF_PROJECTED) { case D3DTTFF_DISABLE: renderer->setTextureTransform(stage, 0, (value & D3DTTFF_PROJECTED) == D3DTTFF_PROJECTED); break; case D3DTTFF_COUNT1: renderer->setTextureTransform(stage, 1, (value & D3DTTFF_PROJECTED) == D3DTTFF_PROJECTED); break; case D3DTTFF_COUNT2: renderer->setTextureTransform(stage, 2, (value & D3DTTFF_PROJECTED) == D3DTTFF_PROJECTED); break; case D3DTTFF_COUNT3: renderer->setTextureTransform(stage, 3, (value & D3DTTFF_PROJECTED) == D3DTTFF_PROJECTED); break; case D3DTTFF_COUNT4: renderer->setTextureTransform(stage, 4, (value & D3DTTFF_PROJECTED) == D3DTTFF_PROJECTED); break; default: ASSERT(false); } break; case D3DTSS_COLORARG0: switch(value & D3DTA_SELECTMASK) { case D3DTA_CURRENT: renderer->setThirdArgument(stage, sw::TextureStage::SOURCE_CURRENT); break; case D3DTA_DIFFUSE: renderer->setThirdArgument(stage, sw::TextureStage::SOURCE_DIFFUSE); break; case D3DTA_SPECULAR: renderer->setThirdArgument(stage, sw::TextureStage::SOURCE_SPECULAR); break; case D3DTA_TEMP: renderer->setThirdArgument(stage, sw::TextureStage::SOURCE_TEMP); break; case D3DTA_TEXTURE: renderer->setThirdArgument(stage, sw::TextureStage::SOURCE_TEXTURE); break; case D3DTA_TFACTOR: renderer->setThirdArgument(stage, sw::TextureStage::SOURCE_TFACTOR); break; default: ASSERT(false); } switch(value & ~D3DTA_SELECTMASK) { case 0: renderer->setThirdModifier(stage, sw::TextureStage::MODIFIER_COLOR); break; case D3DTA_COMPLEMENT: renderer->setThirdModifier(stage, sw::TextureStage::MODIFIER_INVCOLOR); break; case D3DTA_ALPHAREPLICATE: renderer->setThirdModifier(stage, sw::TextureStage::MODIFIER_ALPHA); break; case D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE: renderer->setThirdModifier(stage, sw::TextureStage::MODIFIER_INVALPHA); break; default: ASSERT(false); } break; case D3DTSS_ALPHAARG0: switch(value & D3DTA_SELECTMASK) { case D3DTA_DIFFUSE: renderer->setThirdArgumentAlpha(stage, sw::TextureStage::SOURCE_DIFFUSE); break; case D3DTA_CURRENT: renderer->setThirdArgumentAlpha(stage, sw::TextureStage::SOURCE_CURRENT); break; case D3DTA_TEXTURE: renderer->setThirdArgumentAlpha(stage, sw::TextureStage::SOURCE_TEXTURE); break; case D3DTA_TFACTOR: renderer->setThirdArgumentAlpha(stage, sw::TextureStage::SOURCE_TFACTOR); break; case D3DTA_SPECULAR: renderer->setThirdArgumentAlpha(stage, sw::TextureStage::SOURCE_SPECULAR); break; case D3DTA_TEMP: renderer->setThirdArgumentAlpha(stage, sw::TextureStage::SOURCE_TEMP); break; case D3DTA_CONSTANT: renderer->setThirdArgumentAlpha(stage, sw::TextureStage::SOURCE_CONSTANT); break; default: ASSERT(false); } switch(value & ~D3DTA_SELECTMASK) { case 0: renderer->setThirdModifierAlpha(stage, sw::TextureStage::MODIFIER_COLOR); break; case D3DTA_COMPLEMENT: renderer->setThirdModifierAlpha(stage, sw::TextureStage::MODIFIER_INVCOLOR); break; case D3DTA_ALPHAREPLICATE: renderer->setThirdModifierAlpha(stage, sw::TextureStage::MODIFIER_ALPHA); break; case D3DTA_COMPLEMENT | D3DTA_ALPHAREPLICATE: renderer->setThirdModifierAlpha(stage, sw::TextureStage::MODIFIER_INVALPHA); break; default: ASSERT(false); } break; case D3DTSS_RESULTARG: switch(value & D3DTA_SELECTMASK) { case D3DTA_CURRENT: renderer->setDestinationArgument(stage, sw::TextureStage::DESTINATION_CURRENT); break; case D3DTA_TEMP: renderer->setDestinationArgument(stage, sw::TextureStage::DESTINATION_TEMP); break; default: ASSERT(false); } break; case D3DTSS_CONSTANT: renderer->setConstantColor(stage, value); break; default: ASSERT(false); } } else // stateRecorder { stateRecorder->setTextureStageState(stage, type, value); } return D3D_OK; } long Direct3DDevice9::SetTransform(D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix) { CriticalSection cs(this); TRACE("D3DTRANSFORMSTATETYPE state = %d, const D3DMATRIX *matrix = 0x%0.8p", state, matrix); if(!matrix) { return INVALIDCALL(); } if(!stateRecorder) { this->matrix[state] = *matrix; sw::Matrix M(matrix->_11, matrix->_21, matrix->_31, matrix->_41, matrix->_12, matrix->_22, matrix->_32, matrix->_42, matrix->_13, matrix->_23, matrix->_33, matrix->_43, matrix->_14, matrix->_24, matrix->_34, matrix->_44); switch(state) { case D3DTS_WORLD: renderer->setModelMatrix(M); break; case D3DTS_VIEW: renderer->setViewMatrix(M); break; case D3DTS_PROJECTION: renderer->setProjectionMatrix(M); break; case D3DTS_TEXTURE0: renderer->setTextureMatrix(0, M); break; case D3DTS_TEXTURE1: renderer->setTextureMatrix(1, M); break; case D3DTS_TEXTURE2: renderer->setTextureMatrix(2, M); break; case D3DTS_TEXTURE3: renderer->setTextureMatrix(3, M); break; case D3DTS_TEXTURE4: renderer->setTextureMatrix(4, M); break; case D3DTS_TEXTURE5: renderer->setTextureMatrix(5, M); break; case D3DTS_TEXTURE6: renderer->setTextureMatrix(6, M); break; case D3DTS_TEXTURE7: renderer->setTextureMatrix(7, M); break; default: if(state > 256 && state < 512) { renderer->setModelMatrix(M, state - 256); } else ASSERT(false); } } else // stateRecorder { stateRecorder->setTransform(state, matrix); } return D3D_OK; } long Direct3DDevice9::SetVertexDeclaration(IDirect3DVertexDeclaration9 *iVertexDeclaration) { CriticalSection cs(this); TRACE("IDirect3DVertexDeclaration9 *declaration = 0x%0.8p", iVertexDeclaration); Direct3DVertexDeclaration9 *vertexDeclaration = static_cast<Direct3DVertexDeclaration9*>(iVertexDeclaration); if(!stateRecorder) { if(this->vertexDeclaration == vertexDeclaration) { return D3D_OK; } if(vertexDeclaration) { vertexDeclaration->bind(); } if(this->vertexDeclaration) { this->vertexDeclaration->unbind(); } this->vertexDeclaration = vertexDeclaration; } else { stateRecorder->setVertexDeclaration(vertexDeclaration); } return D3D_OK; } long Direct3DDevice9::SetVertexShader(IDirect3DVertexShader9 *iVertexShader) { CriticalSection cs(this); TRACE("IDirect3DVertexShader9 *shader = 0x%0.8p", iVertexShader); Direct3DVertexShader9 *vertexShader = static_cast<Direct3DVertexShader9*>(iVertexShader); if(!stateRecorder) { if(this->vertexShader == vertexShader) { return D3D_OK; } if(vertexShader) { vertexShader->bind(); } if(this->vertexShader) { this->vertexShader->unbind(); } this->vertexShader = vertexShader; vertexShaderDirty = true; } else { stateRecorder->setVertexShader(vertexShader); } return D3D_OK; } long Direct3DDevice9::SetVertexShaderConstantB(unsigned int startRegister, const int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } if(!stateRecorder) { for(unsigned int i = 0; i < count && startRegister + i < 16; i++) { vertexShaderConstantB[startRegister + i] = constantData[i]; } vertexShaderConstantsBDirty = sw::max(startRegister + count, vertexShaderConstantsBDirty); vertexShaderDirty = true; // Reload DEF constants } else { stateRecorder->setVertexShaderConstantB(startRegister, constantData, count); } return D3D_OK; } long Direct3DDevice9::SetVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } if(!stateRecorder) { for(unsigned int i = 0; i < count && startRegister + i < MAX_VERTEX_SHADER_CONST; i++) { vertexShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0]; vertexShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1]; vertexShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2]; vertexShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3]; } vertexShaderConstantsFDirty = sw::max(startRegister + count, vertexShaderConstantsFDirty); vertexShaderDirty = true; // Reload DEF constants } else { stateRecorder->setVertexShaderConstantF(startRegister, constantData, count); } return D3D_OK; } long Direct3DDevice9::SetVertexShaderConstantI(unsigned int startRegister, const int *constantData, unsigned int count) { CriticalSection cs(this); TRACE("unsigned int startRegister = %d, const int *constantData = 0x%0.8p, unsigned int count = %d", startRegister, constantData, count); if(!constantData) { return INVALIDCALL(); } if(!stateRecorder) { for(unsigned int i = 0; i < count && startRegister + i < 16; i++) { vertexShaderConstantI[startRegister + i][0] = constantData[i * 4 + 0]; vertexShaderConstantI[startRegister + i][1] = constantData[i * 4 + 1]; vertexShaderConstantI[startRegister + i][2] = constantData[i * 4 + 2]; vertexShaderConstantI[startRegister + i][3] = constantData[i * 4 + 3]; } vertexShaderConstantsIDirty = sw::max(startRegister + count, vertexShaderConstantsIDirty); vertexShaderDirty = true; // Reload DEF constants } else { stateRecorder->setVertexShaderConstantI(startRegister, constantData, count); } return D3D_OK; } long Direct3DDevice9::SetViewport(const D3DVIEWPORT9 *viewport) { CriticalSection cs(this); TRACE("const D3DVIEWPORT9 *viewport = 0x%0.8p", viewport); if(!viewport) // FIXME: Check if valid { return INVALIDCALL(); } if(!stateRecorder) { this->viewport = *viewport; } else { stateRecorder->setViewport(viewport); } return D3D_OK; } int Direct3DDevice9::ShowCursor(int show) { CriticalSection cs(this); TRACE("int show = %d", show); int oldValue = showCursor ? TRUE : FALSE; showCursor = show != FALSE; if(showCursor) { sw::FrameBuffer::setCursorImage(cursor); } else { sw::FrameBuffer::setCursorImage(0); } return oldValue; } long Direct3DDevice9::StretchRect(IDirect3DSurface9 *sourceSurface, const RECT *sourceRect, IDirect3DSurface9 *destSurface, const RECT *destRect, D3DTEXTUREFILTERTYPE filter) { CriticalSection cs(this); TRACE("IDirect3DSurface9 *sourceSurface = 0x%0.8p, const RECT *sourceRect = 0x%0.8p, IDirect3DSurface9 *destSurface = 0x%0.8p, const RECT *destRect = 0x%0.8p, D3DTEXTUREFILTERTYPE filter = %d", sourceSurface, sourceRect, destSurface, destRect, filter); if(!sourceSurface || !destSurface || !validRectangle(sourceRect, sourceSurface) || !validRectangle(destRect, destSurface)) { return INVALIDCALL(); } D3DSURFACE_DESC sourceDescription; D3DSURFACE_DESC destDescription; sourceSurface->GetDesc(&sourceDescription); destSurface->GetDesc(&destDescription); if(sourceDescription.Pool != D3DPOOL_DEFAULT || destDescription.Pool != D3DPOOL_DEFAULT) { return INVALIDCALL(); } Direct3DSurface9 *source = static_cast<Direct3DSurface9*>(sourceSurface); Direct3DSurface9 *dest = static_cast<Direct3DSurface9*>(destSurface); stretchRect(source, sourceRect, dest, destRect, filter); return D3D_OK; } long Direct3DDevice9::TestCooperativeLevel() { CriticalSection cs(this); TRACE("void"); return D3D_OK; } long Direct3DDevice9::UpdateSurface(IDirect3DSurface9 *sourceSurface, const RECT *sourceRect, IDirect3DSurface9 *destinationSurface, const POINT *destPoint) { CriticalSection cs(this); TRACE("IDirect3DSurface9 *sourceSurface = 0x%0.8p, const RECT *sourceRect = 0x%0.8p, IDirect3DSurface9 *destinationSurface = 0x%0.8p, const POINT *destPoint = 0x%0.8p", sourceSurface, sourceRect, destinationSurface, destPoint); if(!sourceSurface || !destinationSurface) { return INVALIDCALL(); } D3DSURFACE_DESC sourceDescription; D3DSURFACE_DESC destinationDescription; sourceSurface->GetDesc(&sourceDescription); destinationSurface->GetDesc(&destinationDescription); RECT sRect; RECT dRect; if(sourceRect) { sRect.left = sourceRect->left; sRect.top = sourceRect->top; sRect.right = sourceRect->right; sRect.bottom = sourceRect->bottom; } else { sRect.left = 0; sRect.top = 0; sRect.right = sourceDescription.Width; sRect.bottom = sourceDescription.Height; } if(destPoint) { dRect.left = destPoint->x; dRect.top = destPoint->y; dRect.right = destPoint->x + sRect.right - sRect.left; dRect.bottom = destPoint->y + sRect.bottom - sRect.top; } else { dRect.left = 0; dRect.top = 0; dRect.right = sRect.right - sRect.left; dRect.bottom = sRect.bottom - sRect.top; } if(!validRectangle(&sRect, sourceSurface) || !validRectangle(&dRect, destinationSurface)) { return INVALIDCALL(); } int sWidth = sRect.right - sRect.left; int sHeight = sRect.bottom - sRect.top; int dWidth = dRect.right - dRect.left; int dHeight = dRect.bottom - dRect.top; if(sourceDescription.MultiSampleType != D3DMULTISAMPLE_NONE || destinationDescription.MultiSampleType != D3DMULTISAMPLE_NONE || // sourceDescription.Pool != D3DPOOL_SYSTEMMEM || // FIXME: Check back buffer and depth buffer memory pool flags // destinationDescription.Pool != D3DPOOL_DEFAULT || sourceDescription.Format != destinationDescription.Format) { return INVALIDCALL(); } sw::Surface *source = static_cast<Direct3DSurface9*>(sourceSurface); sw::Surface *dest = static_cast<Direct3DSurface9*>(destinationSurface); unsigned char *sBuffer = (unsigned char*)source->lockExternal(sRect.left, sRect.top, 0, sw::LOCK_READONLY, sw::PUBLIC); unsigned char *dBuffer = (unsigned char*)dest->lockExternal(dRect.left, dRect.top, 0, sw::LOCK_WRITEONLY, sw::PUBLIC); int sPitch = source->getExternalPitchB(); int dPitch = dest->getExternalPitchB(); unsigned int width; unsigned int height; unsigned int bytes; switch(sourceDescription.Format) { case D3DFMT_DXT1: case D3DFMT_ATI1: width = (dWidth + 3) / 4; height = (dHeight + 3) / 4; bytes = width * 8; // 64 bit per 4x4 block break; case D3DFMT_DXT2: case D3DFMT_DXT3: case D3DFMT_DXT4: case D3DFMT_DXT5: case D3DFMT_ATI2: width = (dWidth + 3) / 4; height = (dHeight + 3) / 4; bytes = width * 16; // 128 bit per 4x4 block break; default: width = dWidth; height = dHeight; bytes = width * Direct3DSurface9::bytes(sourceDescription.Format); } if(sourceDescription.Format == D3DFMT_ATI1 || sourceDescription.Format == D3DFMT_ATI2) { // Make the pitch correspond to 4 rows sPitch *= 4; dPitch *= 4; } for(unsigned int y = 0; y < height; y++) { memcpy(dBuffer, sBuffer, bytes); sBuffer += sPitch; dBuffer += dPitch; } source->unlockExternal(); dest->unlockExternal(); return D3D_OK; } long Direct3DDevice9::UpdateTexture(IDirect3DBaseTexture9 *sourceTexture, IDirect3DBaseTexture9 *destinationTexture) { CriticalSection cs(this); TRACE("IDirect3DBaseTexture9 *sourceTexture = 0x%0.8p, IDirect3DBaseTexture9 *destinationTexture = 0x%0.8p", sourceTexture, destinationTexture); if(!sourceTexture || !destinationTexture) { return INVALIDCALL(); } // FIXME: Check memory pools D3DRESOURCETYPE type = sourceTexture->GetType(); if(type != destinationTexture->GetType()) { return INVALIDCALL(); } switch(type) { case D3DRTYPE_TEXTURE: { IDirect3DTexture9 *source; IDirect3DTexture9 *dest; sourceTexture->QueryInterface(IID_IDirect3DTexture9, (void**)&source); destinationTexture->QueryInterface(IID_IDirect3DTexture9, (void**)&dest); ASSERT(source && dest); for(unsigned int level = 0; level < source->GetLevelCount() && level < dest->GetLevelCount(); level++) // FIXME: Fail when source texture has fewer levels than the destination { IDirect3DSurface9 *sourceSurface; IDirect3DSurface9 *destinationSurface; source->GetSurfaceLevel(level, &sourceSurface); dest->GetSurfaceLevel(level, &destinationSurface); UpdateSurface(sourceSurface, 0, destinationSurface, 0); sourceSurface->Release(); destinationSurface->Release(); } source->Release(); dest->Release(); } break; case D3DRTYPE_VOLUMETEXTURE: { IDirect3DVolumeTexture9 *source; IDirect3DVolumeTexture9 *dest; sourceTexture->QueryInterface(IID_IDirect3DVolumeTexture9, (void**)&source); destinationTexture->QueryInterface(IID_IDirect3DVolumeTexture9, (void**)&dest); ASSERT(source && dest); for(unsigned int level = 0; level < source->GetLevelCount() && level < dest->GetLevelCount(); level++) // FIXME: Fail when source texture has fewer levels than the destination { IDirect3DVolume9 *sourceVolume; IDirect3DVolume9 *destinationVolume; source->GetVolumeLevel(level, &sourceVolume); dest->GetVolumeLevel(level, &destinationVolume); updateVolume(sourceVolume, destinationVolume); sourceVolume->Release(); destinationVolume->Release(); } source->Release(); dest->Release(); } break; case D3DRTYPE_CUBETEXTURE: { IDirect3DCubeTexture9 *source; IDirect3DCubeTexture9 *dest; sourceTexture->QueryInterface(IID_IDirect3DCubeTexture9, (void**)&source); destinationTexture->QueryInterface(IID_IDirect3DCubeTexture9, (void**)&dest); ASSERT(source && dest); for(int face = 0; face < 6; face++) { for(unsigned int level = 0; level < source->GetLevelCount() && level < dest->GetLevelCount(); level++) // FIXME: Fail when source texture has fewer levels than the destination { IDirect3DSurface9 *sourceSurface; IDirect3DSurface9 *destinationSurface; source->GetCubeMapSurface((D3DCUBEMAP_FACES)face, level, &sourceSurface); dest->GetCubeMapSurface((D3DCUBEMAP_FACES)face, level, &destinationSurface); UpdateSurface(sourceSurface, 0, destinationSurface, 0); sourceSurface->Release(); destinationSurface->Release(); } } source->Release(); dest->Release(); } break; default: UNIMPLEMENTED(); } return D3D_OK; } long Direct3DDevice9::ValidateDevice(unsigned long *numPasses) { CriticalSection cs(this); TRACE("unsigned long *numPasses = 0x%0.8p", numPasses); if(!numPasses) { return INVALIDCALL(); } *numPasses = 1; return D3D_OK; } long Direct3DDevice9::getAdapterDisplayMode(unsigned int adapter, D3DDISPLAYMODE *mode) { return d3d9->GetAdapterDisplayMode(adapter, mode); } int Direct3DDevice9::typeStride(unsigned char streamType) { static int LUT[] = { 4, // D3DDECLTYPE_FLOAT1 = 0, // 1D float expanded to (value, 0., 0., 1.) 8, // D3DDECLTYPE_FLOAT2 = 1, // 2D float expanded to (value, value, 0., 1.) 12, // D3DDECLTYPE_FLOAT3 = 2, // 3D float expanded to (value, value, value, 1.) 16, // D3DDECLTYPE_FLOAT4 = 3, // 4D float 4, // D3DDECLTYPE_D3DCOLOR = 4, // 4D packed unsigned bytes mapped to 0. to 1. range. Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A) 4, // D3DDECLTYPE_UBYTE4 = 5, // 4D unsigned byte 4, // D3DDECLTYPE_SHORT2 = 6, // 2D signed short expanded to (value, value, 0., 1.) 8, // D3DDECLTYPE_SHORT4 = 7, // 4D signed short 4, // D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0 4, // D3DDECLTYPE_SHORT2N = 9, // 2D signed short normalized (v[0]/32767.0,v[1]/32767.0,0,1) 8, // D3DDECLTYPE_SHORT4N = 10, // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0) 4, // D3DDECLTYPE_USHORT2N = 11, // 2D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,0,1) 8, // D3DDECLTYPE_USHORT4N = 12, // 4D unsigned short normalized (v[0]/65535.0,v[1]/65535.0,v[2]/65535.0,v[3]/65535.0) 4, // D3DDECLTYPE_UDEC3 = 13, // 3D unsigned 10 10 10 format expanded to (value, value, value, 1) 4, // D3DDECLTYPE_DEC3N = 14, // 3D signed 10 10 10 format normalized and expanded to (v[0]/511.0, v[1]/511.0, v[2]/511.0, 1) 4, // D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1) 8, // D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values 0, // D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused. }; return LUT[streamType]; } bool Direct3DDevice9::instanceData() { ASSERT(vertexDeclaration); D3DVERTEXELEMENT9 vertexElement[MAXD3DDECLLENGTH + 1]; unsigned int numElements; vertexDeclaration->GetDeclaration(vertexElement, &numElements); bool instanceData = false; for(unsigned int i = 0; i < numElements - 1; i++) { unsigned short stream = vertexElement[i].Stream; if(stream != 0) { instanceData = instanceData || (streamSourceFreq[stream] & D3DSTREAMSOURCE_INSTANCEDATA) != 0; } } return instanceData; } bool Direct3DDevice9::bindResources(Direct3DIndexBuffer9 *indexBuffer) { if(!bindViewport()) { return false; // Zero-area target region } bindTextures(); bindIndexBuffer(indexBuffer); bindShaderConstants(); bindLights(); return true; } void Direct3DDevice9::bindVertexStreams(int base, bool instancing, int instance) { ASSERT(vertexDeclaration); renderer->resetInputStreams(vertexDeclaration->isPreTransformed()); D3DVERTEXELEMENT9 vertexElement[MAXD3DDECLLENGTH + 1]; unsigned int numElements; vertexDeclaration->GetDeclaration(vertexElement, &numElements); // Bind vertex data streams for(unsigned int i = 0; i < numElements - 1; i++) { unsigned short stream = vertexElement[i].Stream; unsigned short offset = vertexElement[i].Offset; unsigned char type = vertexElement[i].Type; unsigned char method = vertexElement[i].Method; unsigned char usage = vertexElement[i].Usage; unsigned char index = vertexElement[i].UsageIndex; ASSERT(method == D3DDECLMETHOD_DEFAULT); // FIXME: Unimplemented if(!dataStream[stream]) { continue; } Direct3DVertexBuffer9 *streamBuffer = dataStream[stream]; sw::Resource *resource = streamBuffer->getResource(); const void *buffer = ((char*)resource->data() + streamOffset[stream]) + offset; int stride = streamStride[stream]; if(instancing && streamSourceFreq[stream] & D3DSTREAMSOURCE_INSTANCEDATA) { int instanceFrequency = streamSourceFreq[stream] & ~D3DSTREAMSOURCE_INSTANCEDATA; buffer = (char*)buffer + stride * (instance / instanceFrequency); stride = 0; } else { buffer = (char*)buffer + stride * base; } sw::Stream attribute(resource, buffer, stride); switch(type) { case D3DDECLTYPE_FLOAT1: attribute.define(sw::STREAMTYPE_FLOAT, 1, false); break; case D3DDECLTYPE_FLOAT2: attribute.define(sw::STREAMTYPE_FLOAT, 2, false); break; case D3DDECLTYPE_FLOAT3: attribute.define(sw::STREAMTYPE_FLOAT, 3, false); break; case D3DDECLTYPE_FLOAT4: attribute.define(sw::STREAMTYPE_FLOAT, 4, false); break; case D3DDECLTYPE_D3DCOLOR: attribute.define(sw::STREAMTYPE_COLOR, 4, false); break; case D3DDECLTYPE_UBYTE4: attribute.define(sw::STREAMTYPE_BYTE, 4, false); break; case D3DDECLTYPE_SHORT2: attribute.define(sw::STREAMTYPE_SHORT, 2, false); break; case D3DDECLTYPE_SHORT4: attribute.define(sw::STREAMTYPE_SHORT, 4, false); break; case D3DDECLTYPE_UBYTE4N: attribute.define(sw::STREAMTYPE_BYTE, 4, true); break; case D3DDECLTYPE_SHORT2N: attribute.define(sw::STREAMTYPE_SHORT, 2, true); break; case D3DDECLTYPE_SHORT4N: attribute.define(sw::STREAMTYPE_SHORT, 4, true); break; case D3DDECLTYPE_USHORT2N: attribute.define(sw::STREAMTYPE_USHORT, 2, true); break; case D3DDECLTYPE_USHORT4N: attribute.define(sw::STREAMTYPE_USHORT, 4, true); break; case D3DDECLTYPE_UDEC3: attribute.define(sw::STREAMTYPE_UDEC3, 3, false); break; case D3DDECLTYPE_DEC3N: attribute.define(sw::STREAMTYPE_DEC3N, 3, true); break; case D3DDECLTYPE_FLOAT16_2: attribute.define(sw::STREAMTYPE_HALF, 2, false); break; case D3DDECLTYPE_FLOAT16_4: attribute.define(sw::STREAMTYPE_HALF, 4, false); break; case D3DDECLTYPE_UNUSED: attribute.defaults(); break; default: ASSERT(false); } if(vertexShader) { const sw::VertexShader *shader = vertexShader->getVertexShader(); if(!vertexDeclaration->isPreTransformed()) { for(int i = 0; i < MAX_VERTEX_INPUTS; i++) { const sw::Shader::Semantic& input = shader->getInput(i); if((usage == input.usage) && (index == input.index)) { renderer->setInputStream(i, attribute); break; } } } else // Bind directly to the output { for(int i = 0; i < MAX_VERTEX_OUTPUTS; i++) { const sw::Shader::Semantic& output = shader->getOutput(i, 0); if(((usage == output.usage) || (usage == D3DDECLUSAGE_POSITIONT && output.usage == D3DDECLUSAGE_POSITION)) && (index == output.index)) { renderer->setInputStream(i, attribute); break; } } } } else { switch(usage) { case D3DDECLUSAGE_POSITION: renderer->setInputStream(sw::Position, attribute); break; case D3DDECLUSAGE_BLENDWEIGHT: renderer->setInputStream(sw::BlendWeight, attribute); break; case D3DDECLUSAGE_BLENDINDICES: renderer->setInputStream(sw::BlendIndices, attribute.define(sw::STREAMTYPE_INDICES, 1)); break; case D3DDECLUSAGE_NORMAL: renderer->setInputStream(sw::Normal, attribute.define(sw::STREAMTYPE_FLOAT, 3)); break; case D3DDECLUSAGE_PSIZE: renderer->setInputStream(sw::PointSize, attribute.define(sw::STREAMTYPE_FLOAT, 1)); break; case D3DDECLUSAGE_TEXCOORD: renderer->setInputStream(sw::TexCoord0 + index, attribute); break; case D3DDECLUSAGE_TANGENT: /* Ignored */ break; case D3DDECLUSAGE_BINORMAL: /* Ignored */ break; case D3DDECLUSAGE_TESSFACTOR: UNIMPLEMENTED(); break; case D3DDECLUSAGE_POSITIONT: renderer->setInputStream(sw::PositionT, attribute.define(sw::STREAMTYPE_FLOAT, 4)); break; case D3DDECLUSAGE_COLOR: renderer->setInputStream(sw::Color0 + index, attribute.define(sw::STREAMTYPE_COLOR, 4)); break; case D3DDECLUSAGE_FOG: /* Ignored */ break; case D3DDECLUSAGE_DEPTH: /* Ignored */ break; case D3DDECLUSAGE_SAMPLE: UNIMPLEMENTED(); break; default: ASSERT(false); } } } } void Direct3DDevice9::bindIndexBuffer(Direct3DIndexBuffer9 *indexBuffer) { sw::Resource *resource = 0; if(indexBuffer) { resource = indexBuffer->getResource(); } renderer->setIndexBuffer(resource); } void Direct3DDevice9::bindShaderConstants() { if(pixelShaderDirty) { if(pixelShader) { if(pixelShaderConstantsBDirty) { renderer->setPixelShaderConstantB(0, pixelShaderConstantB, pixelShaderConstantsBDirty); } if(pixelShaderConstantsFDirty) { renderer->setPixelShaderConstantF(0, pixelShaderConstantF[0], pixelShaderConstantsFDirty); } if(pixelShaderConstantsIDirty) { renderer->setPixelShaderConstantI(0, pixelShaderConstantI[0], pixelShaderConstantsIDirty); } renderer->setPixelShader(pixelShader->getPixelShader()); // Loads shader constants set with DEF pixelShaderConstantsBDirty = pixelShader->getPixelShader()->dirtyConstantsB; // Shader DEF'ed constants are dirty pixelShaderConstantsFDirty = pixelShader->getPixelShader()->dirtyConstantsF; // Shader DEF'ed constants are dirty pixelShaderConstantsIDirty = pixelShader->getPixelShader()->dirtyConstantsI; // Shader DEF'ed constants are dirty } else { renderer->setPixelShader(0); } pixelShaderDirty = false; } if(vertexShaderDirty) { if(vertexShader) { if(vertexShaderConstantsBDirty) { renderer->setVertexShaderConstantB(0, vertexShaderConstantB, vertexShaderConstantsBDirty); } if(vertexShaderConstantsFDirty) { renderer->setVertexShaderConstantF(0, vertexShaderConstantF[0], vertexShaderConstantsFDirty); } if(vertexShaderConstantsIDirty) { renderer->setVertexShaderConstantI(0, vertexShaderConstantI[0], vertexShaderConstantsIDirty); } renderer->setVertexShader(vertexShader->getVertexShader()); // Loads shader constants set with DEF vertexShaderConstantsBDirty = vertexShader->getVertexShader()->dirtyConstantsB; // Shader DEF'ed constants are dirty vertexShaderConstantsFDirty = vertexShader->getVertexShader()->dirtyConstantsF; // Shader DEF'ed constants are dirty vertexShaderConstantsIDirty = vertexShader->getVertexShader()->dirtyConstantsI; // Shader DEF'ed constants are dirty } else { renderer->setVertexShader(0); } vertexShaderDirty = false; } } void Direct3DDevice9::bindLights() { if(!lightsDirty) return; Lights::iterator i = light.begin(); int active = 0; // Set and enable renderer lights while(active < 8) { while(i != light.end() && !i->second.enable) { i++; } if(i == light.end()) { break; } const Light &l = i->second; sw::Point position(l.Position.x, l.Position.y, l.Position.z); sw::Color<float> diffuse(l.Diffuse.r, l.Diffuse.g, l.Diffuse.b, l.Diffuse.a); sw::Color<float> specular(l.Specular.r, l.Specular.g, l.Specular.b, l.Specular.a); sw::Color<float> ambient(l.Ambient.r, l.Ambient.g, l.Ambient.b, l.Ambient.a); sw::Vector direction(l.Direction.x, l.Direction.y, l.Direction.z); renderer->setLightDiffuse(active, diffuse); renderer->setLightSpecular(active, specular); renderer->setLightAmbient(active, ambient); if(l.Type == D3DLIGHT_DIRECTIONAL) { // FIXME: Unsupported, make it a positional light far away without falloff renderer->setLightPosition(active, -1e10f * direction); renderer->setLightRange(active, l.Range); renderer->setLightAttenuation(active, 1, 0, 0); } else if(l.Type == D3DLIGHT_SPOT) { // FIXME: Unsupported, make it a positional light renderer->setLightPosition(active, position); renderer->setLightRange(active, l.Range); renderer->setLightAttenuation(active, l.Attenuation0, l.Attenuation1, l.Attenuation2); } else { renderer->setLightPosition(active, position); renderer->setLightRange(active, l.Range); renderer->setLightAttenuation(active, l.Attenuation0, l.Attenuation1, l.Attenuation2); } renderer->setLightEnable(active, true); active++; i++; } // Remaining lights are disabled while(active < 8) { renderer->setLightEnable(active, false); active++; } lightsDirty = false; } bool Direct3DDevice9::bindViewport() { if(viewport.Width <= 0 || viewport.Height <= 0) { return false; } if(scissorEnable) { if(scissorRect.left >= scissorRect.right || scissorRect.top >= scissorRect.bottom) { return false; } sw::Rect scissor; scissor.x0 = scissorRect.left; scissor.x1 = scissorRect.right; scissor.y0 = scissorRect.top; scissor.y1 = scissorRect.bottom; renderer->setScissor(scissor); } else { sw::Rect scissor; scissor.x0 = viewport.X; scissor.x1 = viewport.X + viewport.Width; scissor.y0 = viewport.Y; scissor.y1 = viewport.Y + viewport.Height; renderer->setScissor(scissor); } sw::Viewport view; view.x0 = (float)viewport.X; view.y0 = (float)viewport.Y + viewport.Height; view.width = (float)viewport.Width; view.height = -(float)viewport.Height; view.minZ = viewport.MinZ; view.maxZ = viewport.MaxZ; renderer->setViewport(view); return true; } void Direct3DDevice9::bindTextures() { for(int sampler = 0; sampler < 16 + 4; sampler++) { Direct3DBaseTexture9 *baseTexture = texture[sampler]; sw::SamplerType type = sampler < 16 ? sw::SAMPLER_PIXEL : sw::SAMPLER_VERTEX; int index = sampler < 16 ? sampler : sampler - 16; // Sampler index within type group bool textureUsed = false; if(type == sw::SAMPLER_PIXEL && pixelShader) { textureUsed = pixelShader->getPixelShader()->usesSampler(index); } else if(type == sw::SAMPLER_VERTEX && vertexShader) { textureUsed = vertexShader->getVertexShader()->usesSampler(index); } else { textureUsed = true; // FIXME: Check fixed-function use? } sw::Resource *resource = 0; if(baseTexture && textureUsed) { resource = baseTexture->getResource(); } renderer->setTextureResource(sampler, resource); if(baseTexture && textureUsed) { baseTexture->GenerateMipSubLevels(); } if(baseTexture && textureUsed) { int levelCount = baseTexture->getInternalLevelCount(); int textureLOD = baseTexture->GetLOD(); int samplerLOD = samplerState[sampler][D3DSAMP_MAXMIPLEVEL]; int LOD = textureLOD > samplerLOD ? textureLOD : samplerLOD; if(samplerState[sampler][D3DSAMP_MIPFILTER] == D3DTEXF_NONE) { LOD = 0; } switch(baseTexture->GetType()) { case D3DRTYPE_TEXTURE: { Direct3DTexture9 *texture = dynamic_cast<Direct3DTexture9*>(baseTexture); Direct3DSurface9 *surface; for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++) { int surfaceLevel = mipmapLevel; if(surfaceLevel < LOD) { surfaceLevel = LOD; } if(surfaceLevel < 0) { surfaceLevel = 0; } else if(surfaceLevel >= levelCount) { surfaceLevel = levelCount - 1; } surface = texture->getInternalSurfaceLevel(surfaceLevel); renderer->setTextureLevel(sampler, 0, mipmapLevel, surface, sw::TEXTURE_2D); } } break; case D3DRTYPE_CUBETEXTURE: for(int face = 0; face < 6; face++) { Direct3DCubeTexture9 *cubeTexture = dynamic_cast<Direct3DCubeTexture9*>(baseTexture); Direct3DSurface9 *surface; for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++) { int surfaceLevel = mipmapLevel; if(surfaceLevel < LOD) { surfaceLevel = LOD; } if(surfaceLevel < 0) { surfaceLevel = 0; } else if(surfaceLevel >= levelCount) { surfaceLevel = levelCount - 1; } surface = cubeTexture->getInternalCubeMapSurface((D3DCUBEMAP_FACES)face, surfaceLevel); renderer->setTextureLevel(sampler, face, mipmapLevel, surface, sw::TEXTURE_CUBE); } } break; case D3DRTYPE_VOLUMETEXTURE: { Direct3DVolumeTexture9 *volumeTexture = dynamic_cast<Direct3DVolumeTexture9*>(baseTexture); Direct3DVolume9 *volume; for(int mipmapLevel = 0; mipmapLevel < sw::MIPMAP_LEVELS; mipmapLevel++) { int surfaceLevel = mipmapLevel; if(surfaceLevel < LOD) { surfaceLevel = LOD; } if(surfaceLevel < 0) { surfaceLevel = 0; } else if(surfaceLevel >= levelCount) { surfaceLevel = levelCount - 1; } volume = volumeTexture->getInternalVolumeLevel(surfaceLevel); renderer->setTextureLevel(sampler, 0, mipmapLevel, volume, sw::TEXTURE_3D); } } break; default: UNIMPLEMENTED(); } } else { renderer->setTextureLevel(sampler, 0, 0, 0, sw::TEXTURE_NULL); } } } bool Direct3DDevice9::isRecording() const { return stateRecorder != 0; } void Direct3DDevice9::setOcclusionEnabled(bool enable) { renderer->setOcclusionEnabled(enable); } void Direct3DDevice9::removeQuery(sw::Query *query) { renderer->removeQuery(query); } void Direct3DDevice9::addQuery(sw::Query *query) { renderer->addQuery(query); } void Direct3DDevice9::stretchRect(Direct3DSurface9 *source, const RECT *sourceRect, Direct3DSurface9 *dest, const RECT *destRect, D3DTEXTUREFILTERTYPE filter) { D3DSURFACE_DESC sourceDescription; D3DSURFACE_DESC destDescription; source->GetDesc(&sourceDescription); dest->GetDesc(&destDescription); int sWidth = source->getWidth(); int sHeight = source->getHeight(); int dWidth = dest->getWidth(); int dHeight = dest->getHeight(); sw::Rect sRect(0, 0, sWidth, sHeight); sw::Rect dRect(0, 0, dWidth, dHeight); if(sourceRect) { sRect.x0 = sourceRect->left; sRect.y0 = sourceRect->top; sRect.x1 = sourceRect->right; sRect.y1 = sourceRect->bottom; } if(destRect) { dRect.x0 = destRect->left; dRect.y0 = destRect->top; dRect.x1 = destRect->right; dRect.y1 = destRect->bottom; } bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0); bool equalFormats = source->getInternalFormat() == dest->getInternalFormat(); bool depthStencil = (sourceDescription.Usage & D3DUSAGE_DEPTHSTENCIL) == D3DUSAGE_DEPTHSTENCIL; bool alpha0xFF = false; if((sourceDescription.Format == D3DFMT_A8R8G8B8 && destDescription.Format == D3DFMT_X8R8G8B8) || (sourceDescription.Format == D3DFMT_X8R8G8B8 && destDescription.Format == D3DFMT_A8R8G8B8)) { equalFormats = true; alpha0xFF = true; } if(depthStencil) // Copy entirely, internally // FIXME: Check { if(source->hasDepth()) { byte *sourceBuffer = (byte*)source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); byte *destBuffer = (byte*)dest->lockInternal(0, 0, 0, sw::LOCK_DISCARD, sw::PUBLIC); unsigned int width = source->getWidth(); unsigned int height = source->getHeight(); unsigned int pitch = source->getInternalPitchB(); for(unsigned int y = 0; y < height; y++) { memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes sourceBuffer += pitch; destBuffer += pitch; } source->unlockInternal(); dest->unlockInternal(); } if(source->hasStencil()) { byte *sourceBuffer = (byte*)source->lockStencil(0, 0, 0, sw::PUBLIC); byte *destBuffer = (byte*)dest->lockStencil(0, 0, 0, sw::PUBLIC); unsigned int width = source->getWidth(); unsigned int height = source->getHeight(); unsigned int pitch = source->getStencilPitchB(); for(unsigned int y = 0; y < height; y++) { memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes sourceBuffer += pitch; destBuffer += pitch; } source->unlockStencil(); dest->unlockStencil(); } } else if(!scaling && equalFormats) { unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, 0, sw::LOCK_READONLY, sw::PUBLIC); unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, sw::LOCK_READWRITE, sw::PUBLIC); unsigned int sourcePitch = source->getInternalPitchB(); unsigned int destPitch = dest->getInternalPitchB(); unsigned int width = dRect.x1 - dRect.x0; unsigned int height = dRect.y1 - dRect.y0; unsigned int bytes = width * sw::Surface::bytes(source->getInternalFormat()); for(unsigned int y = 0; y < height; y++) { memcpy(destBytes, sourceBytes, bytes); if(alpha0xFF) { for(unsigned int x = 0; x < width; x++) { destBytes[4 * x + 3] = 0xFF; } } sourceBytes += sourcePitch; destBytes += destPitch; } source->unlockInternal(); dest->unlockInternal(); } else { sw::SliceRectF sRectF((float)sRect.x0, (float)sRect.y0, (float)sRect.x1, (float)sRect.y1, 0); renderer->blit(source, sRectF, dest, dRect, filter >= D3DTEXF_LINEAR); } } long Direct3DDevice9::updateVolume(IDirect3DVolume9 *sourceVolume, IDirect3DVolume9 *destinationVolume) { TRACE("IDirect3DVolume9 *sourceVolume = 0x%0.8p, IDirect3DVolume9 *destinationVolume = 0x%0.8p", sourceVolume, destinationVolume); if(!sourceVolume || !destinationVolume) { return INVALIDCALL(); } D3DVOLUME_DESC sourceDescription; D3DVOLUME_DESC destinationDescription; sourceVolume->GetDesc(&sourceDescription); destinationVolume->GetDesc(&destinationDescription); if(sourceDescription.Pool != D3DPOOL_SYSTEMMEM || destinationDescription.Pool != D3DPOOL_DEFAULT || sourceDescription.Format != destinationDescription.Format || sourceDescription.Width != destinationDescription.Width || sourceDescription.Height != destinationDescription.Height || sourceDescription.Depth != destinationDescription.Depth) { return INVALIDCALL(); } sw::Surface *source = static_cast<Direct3DVolume9*>(sourceVolume); sw::Surface *dest = static_cast<Direct3DVolume9*>(destinationVolume); if(source->getExternalPitchB() != dest->getExternalPitchB() || source->getExternalSliceB() != dest->getExternalSliceB()) { UNIMPLEMENTED(); } void *sBuffer = source->lockExternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC); void *dBuffer = dest->lockExternal(0, 0, 0, sw::LOCK_WRITEONLY, sw::PUBLIC); memcpy(dBuffer, sBuffer, source->getExternalSliceB() * sourceDescription.Depth); source->unlockExternal(); dest->unlockExternal(); return D3D_OK; } bool Direct3DDevice9::validRectangle(const RECT *rect, IDirect3DSurface9 *surface) { if(!rect) { return true; } if(rect->right <= rect->left || rect->bottom <= rect->top) { return false; } if(rect->left < 0 || rect->top < 0) { return false; } D3DSURFACE_DESC description; surface->GetDesc(&description); if(rect->right > (int)description.Width || rect->bottom > (int)description.Height) { return false; } return true; } void Direct3DDevice9::configureFPU() { // _controlfp(_PC_24, _MCW_PC); // Single-precision _controlfp(_MCW_EM, _MCW_EM); // Mask all exceptions _controlfp(_RC_NEAR, _MCW_RC); // Round to nearest } }