mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
1223 lines
37 KiB
C++
1223 lines
37 KiB
C++
#include <algorithm>
|
|
|
|
#include <Config/Settings/AlternatePixelCenter.h>
|
|
#include <Config/Settings/ColorKeyMethod.h>
|
|
#include <Config/Settings/SpriteFilter.h>
|
|
#include <Config/Settings/SpriteTexCoord.h>
|
|
#include <Config/Settings/TextureFilter.h>
|
|
#include <Common/Log.h>
|
|
#include <D3dDdi/Device.h>
|
|
#include <D3dDdi/DeviceState.h>
|
|
#include <D3dDdi/DrawPrimitive.h>
|
|
#include <D3dDdi/Log/DeviceFuncsLog.h>
|
|
#include <D3dDdi/Resource.h>
|
|
#include <D3dDdi/ShaderAssembler.h>
|
|
#include <Shaders/VertexFixup.h>
|
|
|
|
#define LOG_DS LOG_DEBUG << "DeviceState::" << __func__ << ": "
|
|
|
|
namespace
|
|
{
|
|
const HANDLE DELETED_RESOURCE = reinterpret_cast<HANDLE>(0xBAADBAAD);
|
|
}
|
|
|
|
namespace D3dDdi
|
|
{
|
|
DeviceState::TempPixelShaderConst::TempPixelShaderConst(
|
|
DeviceState& state, const D3DDDIARG_SETPIXELSHADERCONST& data, const ShaderConstF* registers)
|
|
: m_state(state)
|
|
, m_data(data)
|
|
{
|
|
state.m_device.getOrigVtable().pfnSetPixelShaderConst(state.m_device, &data, ®isters[0][0]);
|
|
}
|
|
|
|
DeviceState::TempPixelShaderConst::~TempPixelShaderConst()
|
|
{
|
|
m_state.m_device.getOrigVtable().pfnSetPixelShaderConst(
|
|
m_state.m_device, &m_data, &m_state.m_pixelShaderConst[m_data.Register][0]);
|
|
}
|
|
|
|
DeviceState::DeviceState(Device& device)
|
|
: m_device(device)
|
|
, m_app{}
|
|
, m_current{}
|
|
, m_pixelShaderConst{}
|
|
, m_pixelShaderConstB{}
|
|
, m_pixelShaderConstI{}
|
|
, m_vertexShaderConst{}
|
|
, m_vertexShaderConstB{}
|
|
, m_vertexShaderConstI{}
|
|
, m_vertexDecl(nullptr)
|
|
, m_changedStates(0)
|
|
, m_maxChangedTextureStage(0)
|
|
, m_changedTextureStageStates{}
|
|
, m_vsVertexFixup(createVertexShader(g_vsVertexFixup))
|
|
, m_textureResource{}
|
|
, m_pixelShader(nullptr)
|
|
, m_isLocked(false)
|
|
, m_spriteMode(false)
|
|
{
|
|
const UINT D3DBLENDOP_ADD = 1;
|
|
const UINT UNINITIALIZED_STATE = 0xBAADBAAD;
|
|
|
|
m_device.getOrigVtable().pfnSetDepthStencil(m_device, &m_current.depthStencil);
|
|
m_device.getOrigVtable().pfnSetPixelShader(m_device, nullptr);
|
|
m_device.getOrigVtable().pfnSetRenderTarget(m_device, &m_current.renderTarget);
|
|
m_device.getOrigVtable().pfnSetVertexShaderDecl(m_device, nullptr);
|
|
m_device.getOrigVtable().pfnSetVertexShaderFunc(m_device, nullptr);
|
|
m_device.getOrigVtable().pfnSetViewport(m_device, &m_current.viewport);
|
|
m_device.getOrigVtable().pfnUpdateWInfo(m_device, &m_current.wInfo);
|
|
m_device.getOrigVtable().pfnSetZRange(m_device, &m_current.zRange);
|
|
|
|
m_current.renderState.fill(UNINITIALIZED_STATE);
|
|
m_current.renderState[D3DDDIRS_ZENABLE] = D3DZB_TRUE;
|
|
m_current.renderState[D3DDDIRS_FILLMODE] = D3DFILL_SOLID;
|
|
m_current.renderState[D3DDDIRS_SHADEMODE] = D3DSHADE_GOURAUD;
|
|
m_current.renderState[D3DDDIRS_LINEPATTERN] = 0;
|
|
m_current.renderState[D3DDDIRS_ZWRITEENABLE] = TRUE;
|
|
m_current.renderState[D3DDDIRS_ALPHATESTENABLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_LASTPIXEL] = TRUE;
|
|
m_current.renderState[D3DDDIRS_SRCBLEND] = D3DBLEND_ONE;
|
|
m_current.renderState[D3DDDIRS_DESTBLEND] = D3DBLEND_ZERO;
|
|
m_current.renderState[D3DDDIRS_CULLMODE] = D3DCULL_CCW;
|
|
m_current.renderState[D3DDDIRS_ZFUNC] = D3DCMP_LESSEQUAL;
|
|
m_current.renderState[D3DDDIRS_ALPHAREF] = 0;
|
|
m_current.renderState[D3DDDIRS_ALPHAFUNC] = D3DCMP_ALWAYS;
|
|
m_current.renderState[D3DDDIRS_DITHERENABLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_ALPHABLENDENABLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_FOGENABLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_SPECULARENABLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_ZVISIBLE] = 0;
|
|
m_current.renderState[D3DDDIRS_FOGCOLOR] = 0;
|
|
m_current.renderState[D3DDDIRS_FOGTABLEMODE] = D3DFOG_NONE;
|
|
m_current.renderState[D3DDDIRS_FOGSTART] = 0;
|
|
m_current.renderState[D3DDDIRS_FOGEND] = 0x3F800000;
|
|
m_current.renderState[D3DDDIRS_FOGDENSITY] = 0x3F800000;
|
|
m_current.renderState[D3DDDIRS_COLORKEYENABLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_EDGEANTIALIAS] = 0;
|
|
m_current.renderState[D3DDDIRS_ZBIAS] = 0;
|
|
m_current.renderState[D3DDDIRS_RANGEFOGENABLE] = FALSE;
|
|
for (UINT i = D3DDDIRS_STIPPLEPATTERN00; i <= D3DDDIRS_STIPPLEPATTERN31; ++i)
|
|
{
|
|
m_current.renderState[i] = 0;
|
|
}
|
|
m_current.renderState[D3DDDIRS_STENCILENABLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_STENCILFAIL] = D3DSTENCILOP_KEEP;
|
|
m_current.renderState[D3DDDIRS_STENCILZFAIL] = D3DSTENCILOP_KEEP;
|
|
m_current.renderState[D3DDDIRS_STENCILPASS] = D3DSTENCILOP_KEEP;
|
|
m_current.renderState[D3DDDIRS_STENCILFUNC] = D3DCMP_ALWAYS;
|
|
m_current.renderState[D3DDDIRS_STENCILREF] = 0;
|
|
m_current.renderState[D3DDDIRS_STENCILMASK] = 0xFFFFFFFF;
|
|
m_current.renderState[D3DDDIRS_STENCILWRITEMASK] = 0xFFFFFFFF;
|
|
m_current.renderState[D3DDDIRS_TEXTUREFACTOR] = 0xFFFFFFFF;
|
|
for (UINT i = D3DDDIRS_WRAP0; i <= D3DDDIRS_WRAP7; ++i)
|
|
{
|
|
m_current.renderState[i] = 0;
|
|
}
|
|
m_current.renderState[D3DDDIRS_CLIPPING] = TRUE;
|
|
m_current.renderState[D3DDDIRS_CLIPPLANEENABLE] = 0;
|
|
m_current.renderState[D3DDDIRS_SOFTWAREVERTEXPROCESSING] = FALSE;
|
|
m_current.renderState[D3DDDIRS_POINTSIZE_MAX] = 0x3F800000;
|
|
m_current.renderState[D3DDDIRS_POINTSIZE] = 0x3F800000;
|
|
m_current.renderState[D3DDDIRS_POINTSIZE_MIN] = 0;
|
|
m_current.renderState[D3DDDIRS_POINTSPRITEENABLE] = 0;
|
|
m_current.renderState[D3DDDIRS_MULTISAMPLEMASK] = 0xFFFFFFFF;
|
|
m_current.renderState[D3DDDIRS_MULTISAMPLEANTIALIAS] = TRUE;
|
|
m_current.renderState[D3DDDIRS_PATCHEDGESTYLE] = FALSE;
|
|
m_current.renderState[D3DDDIRS_PATCHSEGMENTS] = 0x3F800000;
|
|
m_current.renderState[D3DDDIRS_COLORWRITEENABLE] = 0xF;
|
|
m_current.renderState[D3DDDIRS_BLENDOP] = D3DBLENDOP_ADD;
|
|
m_current.renderState[D3DDDIRS_SRGBWRITEENABLE] = FALSE;
|
|
|
|
for (UINT i = 0; i < m_current.renderState.size(); i++)
|
|
{
|
|
if (UNINITIALIZED_STATE != m_current.renderState[i])
|
|
{
|
|
D3DDDIARG_RENDERSTATE data = {};
|
|
data.State = static_cast<D3DDDIRENDERSTATETYPE>(i);
|
|
data.Value = m_current.renderState[i];
|
|
m_device.getOrigVtable().pfnSetRenderState(m_device, &data);
|
|
}
|
|
}
|
|
|
|
for (UINT i = 0; i < m_current.textures.size(); ++i)
|
|
{
|
|
m_device.getOrigVtable().pfnSetTexture(m_device, i, nullptr);
|
|
}
|
|
|
|
for (UINT i = 0; i < m_current.textureStageState.size(); ++i)
|
|
{
|
|
m_current.textureStageState[i].fill(UNINITIALIZED_STATE);
|
|
m_current.textureStageState[i][D3DDDITSS_TEXCOORDINDEX] = i;
|
|
|
|
// When ADDRESSU or ADDRESSV is set to CLAMP, their value is overridden by D3DTSS_ADDRESS.
|
|
// Setting this to CLAMP makes them behave as expected, instead of as WRAP,
|
|
// which would be the default init value set by the runtime.
|
|
m_current.textureStageState[i][D3DTSS_ADDRESS] = D3DTADDRESS_CLAMP;
|
|
|
|
m_current.textureStageState[i][D3DDDITSS_ADDRESSU] = D3DTADDRESS_WRAP;
|
|
m_current.textureStageState[i][D3DDDITSS_ADDRESSV] = D3DTADDRESS_WRAP;
|
|
m_current.textureStageState[i][D3DDDITSS_BORDERCOLOR] = 0;
|
|
m_current.textureStageState[i][D3DDDITSS_MAGFILTER] = D3DTEXF_POINT;
|
|
m_current.textureStageState[i][D3DDDITSS_MINFILTER] = D3DTEXF_POINT;
|
|
m_current.textureStageState[i][D3DDDITSS_MIPFILTER] = D3DTEXF_NONE;
|
|
m_current.textureStageState[i][D3DDDITSS_MIPMAPLODBIAS] = 0;
|
|
m_current.textureStageState[i][D3DDDITSS_MAXMIPLEVEL] = 0;
|
|
m_current.textureStageState[i][D3DDDITSS_MAXANISOTROPY] = 1;
|
|
m_current.textureStageState[i][D3DDDITSS_TEXTURETRANSFORMFLAGS] = D3DTTFF_DISABLE;
|
|
m_current.textureStageState[i][D3DDDITSS_SRGBTEXTURE] = FALSE;
|
|
m_current.textureStageState[i][D3DDDITSS_ADDRESSW] = D3DTADDRESS_WRAP;
|
|
m_current.textureStageState[i][D3DDDITSS_DISABLETEXTURECOLORKEY] = TRUE;
|
|
|
|
for (UINT j = 0; j < m_current.textureStageState[i].size(); ++j)
|
|
{
|
|
if (UNINITIALIZED_STATE != m_current.textureStageState[i][j])
|
|
{
|
|
D3DDDIARG_TEXTURESTAGESTATE data = {};
|
|
data.Stage = i;
|
|
data.State = static_cast<D3DDDITEXTURESTAGESTATETYPE>(j);
|
|
data.Value = m_current.textureStageState[i][j];
|
|
m_device.getOrigVtable().pfnSetTextureStageState(m_device, &data);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_app = m_current;
|
|
updateConfig();
|
|
}
|
|
|
|
std::unique_ptr<void, ResourceDeleter> DeviceState::createVertexShader(const BYTE* code, UINT size)
|
|
{
|
|
D3DDDIARG_CREATEVERTEXSHADERFUNC data = {};
|
|
data.Size = size;
|
|
if (FAILED(m_device.getOrigVtable().pfnCreateVertexShaderFunc(m_device, &data, reinterpret_cast<const UINT*>(code))))
|
|
{
|
|
return nullptr;
|
|
}
|
|
return { data.ShaderHandle, ResourceDeleter(m_device, m_device.getOrigVtable().pfnDeleteVertexShaderFunc) };
|
|
}
|
|
|
|
HRESULT DeviceState::deleteShader(HANDLE shader, HANDLE State::* shaderMember,
|
|
HRESULT(APIENTRY* origDeleteShaderFunc)(HANDLE, HANDLE))
|
|
{
|
|
if (shader == m_current.*shaderMember)
|
|
{
|
|
m_device.flushPrimitives();
|
|
}
|
|
|
|
HRESULT result = origDeleteShaderFunc(m_device, shader);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
if (shader == m_app.*shaderMember)
|
|
{
|
|
m_app.*shaderMember = nullptr;
|
|
}
|
|
if (shader == m_current.*shaderMember)
|
|
{
|
|
m_current.*shaderMember = nullptr;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void DeviceState::disableTextureClamp(UINT stage)
|
|
{
|
|
auto resource = getTextureResource(stage);
|
|
resource->disableClamp();
|
|
m_changedStates |= CS_TEXTURE_STAGE;
|
|
m_changedTextureStageStates[stage].set(D3DDDITSS_ADDRESSU);
|
|
m_changedTextureStageStates[stage].set(D3DDDITSS_ADDRESSV);
|
|
m_maxChangedTextureStage = std::max(stage, m_maxChangedTextureStage);
|
|
}
|
|
|
|
void DeviceState::flush()
|
|
{
|
|
if (0 == m_changedStates || m_isLocked)
|
|
{
|
|
return;
|
|
}
|
|
|
|
prepareTextures();
|
|
|
|
if (m_changedStates & CS_RENDER_STATE)
|
|
{
|
|
updateRenderStates();
|
|
}
|
|
if (m_changedStates & CS_RENDER_TARGET)
|
|
{
|
|
updateRenderTarget();
|
|
}
|
|
if (m_changedStates & CS_SHADER)
|
|
{
|
|
updateShaders();
|
|
}
|
|
if (m_changedStates & CS_STREAM_SOURCE)
|
|
{
|
|
updateStreamSource();
|
|
}
|
|
if (m_changedStates & CS_TEXTURE_STAGE)
|
|
{
|
|
updateTextureStages();
|
|
}
|
|
|
|
m_changedStates = 0;
|
|
m_maxChangedTextureStage = 0;
|
|
}
|
|
|
|
Resource* DeviceState::getTextureResource(UINT stage)
|
|
{
|
|
if (!m_app.textures[stage])
|
|
{
|
|
return nullptr;
|
|
}
|
|
if (!m_textureResource[stage] || *m_textureResource[stage] != m_app.textures[stage])
|
|
{
|
|
m_textureResource[stage] = m_device.getResource(m_app.textures[stage]);
|
|
}
|
|
return m_textureResource[stage];
|
|
}
|
|
|
|
UINT DeviceState::getTextureStageCount() const
|
|
{
|
|
return m_pixelShader ? m_pixelShader->textureStageCount : 0;
|
|
}
|
|
|
|
const DeviceState::VertexDecl& DeviceState::getVertexDecl() const
|
|
{
|
|
static const VertexDecl emptyDecl = {};
|
|
return m_vertexDecl ? *m_vertexDecl : emptyDecl;
|
|
}
|
|
|
|
bool DeviceState::isColorKeyUsed()
|
|
{
|
|
if (!m_app.renderState[D3DDDIRS_COLORKEYENABLE])
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool used = false;
|
|
UINT textureStageCount = getTextureStageCount();
|
|
for (UINT i = 0; i < textureStageCount && !used; ++i)
|
|
{
|
|
used = !m_app.textureStageState[i][D3DDDITSS_DISABLETEXTURECOLORKEY];
|
|
}
|
|
return used;
|
|
}
|
|
|
|
HANDLE DeviceState::mapPixelShader(HANDLE shader)
|
|
{
|
|
if (Config::Settings::ColorKeyMethod::ALPHATEST != Config::colorKeyMethod.get())
|
|
{
|
|
return m_app.pixelShader;
|
|
}
|
|
|
|
auto it = m_pixelShaders.find(shader);
|
|
if (it == m_pixelShaders.end())
|
|
{
|
|
return m_app.pixelShader;
|
|
}
|
|
|
|
if (!it->second.isModified)
|
|
{
|
|
ShaderAssembler shaderAssembler(it->second.tokens.data(), it->second.tokens.size());
|
|
if (shaderAssembler.addAlphaTest(Config::colorKeyMethod.getParam()))
|
|
{
|
|
const auto& tokens = shaderAssembler.getTokens();
|
|
D3DDDIARG_CREATEPIXELSHADER data = {};
|
|
data.CodeSize = tokens.size() * 4;
|
|
HRESULT result = m_device.getOrigVtable().pfnCreatePixelShader(m_device, &data, tokens.data());
|
|
if (SUCCEEDED(result))
|
|
{
|
|
it->second.modifiedPixelShader.reset(data.ShaderHandle);
|
|
}
|
|
else
|
|
{
|
|
LOG_ONCE("ERROR: failed to create modified pixel shader: " << Compat::hex(result));
|
|
}
|
|
}
|
|
it->second.isModified = true;
|
|
}
|
|
|
|
return it->second.modifiedPixelShader ? it->second.modifiedPixelShader.get() : m_app.pixelShader;
|
|
}
|
|
|
|
UINT DeviceState::mapRsValue(D3DDDIRENDERSTATETYPE state, UINT value)
|
|
{
|
|
if (state >= D3DDDIRS_WRAP0 && state <= D3DDDIRS_WRAP7)
|
|
{
|
|
return value & (D3DWRAPCOORD_0 | D3DWRAPCOORD_1 | D3DWRAPCOORD_2 | D3DWRAPCOORD_3);
|
|
}
|
|
|
|
if (D3DDDIRS_COLORKEYENABLE == state)
|
|
{
|
|
if (Config::Settings::ColorKeyMethod::NATIVE != Config::colorKeyMethod.get())
|
|
{
|
|
return FALSE;
|
|
}
|
|
return isColorKeyUsed();
|
|
}
|
|
|
|
if (D3DDDIRS_MULTISAMPLEANTIALIAS == state)
|
|
{
|
|
return 0 != value && !m_spriteMode;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
UINT DeviceState::mapTssValue(UINT stage, D3DDDITEXTURESTAGESTATETYPE state, UINT value)
|
|
{
|
|
switch (state)
|
|
{
|
|
case D3DDDITSS_ADDRESSU:
|
|
case D3DDDITSS_ADDRESSV:
|
|
if (m_spriteMode && D3DTADDRESS_CLAMP != value)
|
|
{
|
|
if (Config::Settings::SpriteTexCoord::CLAMP == Config::spriteTexCoord.get())
|
|
{
|
|
auto resource = getTextureResource(stage);
|
|
if (resource && resource->isClampable())
|
|
{
|
|
return D3DTADDRESS_CLAMP;
|
|
}
|
|
}
|
|
else if (Config::Settings::SpriteTexCoord::CLAMPALL == Config::spriteTexCoord.get())
|
|
{
|
|
return D3DTADDRESS_CLAMP;
|
|
}
|
|
}
|
|
return value;
|
|
|
|
case D3DDDITSS_MAGFILTER:
|
|
case D3DDDITSS_MINFILTER:
|
|
{
|
|
auto filter = (m_spriteMode && 0 == stage) ? Config::spriteFilter.get() : Config::textureFilter.getFilter();
|
|
return D3DTEXF_NONE == filter ? value : filter;
|
|
}
|
|
|
|
case D3DDDITSS_MIPFILTER:
|
|
return D3DTEXF_NONE == Config::textureFilter.getMipFilter() ? value : Config::textureFilter.getMipFilter();
|
|
|
|
case D3DDDITSS_MAXANISOTROPY:
|
|
return D3DTEXF_NONE == Config::textureFilter.getFilter() ? value : Config::textureFilter.getMaxAnisotropy();
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void DeviceState::onDestroyResource(Resource* resource, HANDLE resourceHandle)
|
|
{
|
|
for (UINT i = 0; i < m_current.textures.size(); ++i)
|
|
{
|
|
if (m_current.textures[i] == resourceHandle)
|
|
{
|
|
m_current.textures[i] = DELETED_RESOURCE;
|
|
}
|
|
if (m_app.textures[i] == resourceHandle)
|
|
{
|
|
pfnSetTexture(i, nullptr);
|
|
}
|
|
if (m_textureResource[i] == resource)
|
|
{
|
|
m_textureResource[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
removeResource(resourceHandle, &State::renderTarget, &D3DDDIARG_SETRENDERTARGET::hRenderTarget,
|
|
&DeviceState::pfnSetRenderTarget);
|
|
removeResource(resourceHandle, &State::depthStencil, &D3DDDIARG_SETDEPTHSTENCIL::hZBuffer,
|
|
&DeviceState::pfnSetDepthStencil);
|
|
removeResource(resourceHandle, &State::streamSource, &D3DDDIARG_SETSTREAMSOURCE::hVertexBuffer,
|
|
&DeviceState::pfnSetStreamSource);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnCreatePixelShader(D3DDDIARG_CREATEPIXELSHADER* data, const UINT* code)
|
|
{
|
|
ShaderAssembler shaderAssembler(code, data->CodeSize);
|
|
LOG_DEBUG << "Pixel shader bytecode: " << Compat::hexDump(code, data->CodeSize);
|
|
LOG_DEBUG << shaderAssembler.disassemble();
|
|
HRESULT result = m_device.getOrigVtable().pfnCreatePixelShader(m_device, data, code);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
m_pixelShaders.emplace(data->ShaderHandle,
|
|
PixelShader{ std::vector<UINT>(code, code + data->CodeSize / 4),
|
|
std::unique_ptr<void, ResourceDeleter>(
|
|
nullptr, ResourceDeleter(m_device, m_device.getOrigVtable().pfnDeleteVertexShaderFunc)),
|
|
shaderAssembler.getTextureStageCount(), false });
|
|
}
|
|
return result;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnCreateVertexShaderDecl(
|
|
D3DDDIARG_CREATEVERTEXSHADERDECL* data,
|
|
const D3DDDIVERTEXELEMENT* vertexElements)
|
|
{
|
|
LOG_DEBUG << Compat::array(vertexElements, data->NumVertexElements);
|
|
|
|
const UINT D3DDECLUSAGE_POSITION = 0;
|
|
const UINT D3DDECLUSAGE_TEXCOORD = 5;
|
|
const UINT D3DDECLUSAGE_POSITIONT = 9;
|
|
|
|
std::vector<D3DDDIVERTEXELEMENT> ve(vertexElements, vertexElements + data->NumVertexElements);
|
|
VertexDecl decl = {};
|
|
decl.elements = ve;
|
|
|
|
for (UINT i = 0; i < data->NumVertexElements; ++i)
|
|
{
|
|
if (D3DDECLUSAGE_TEXCOORD == vertexElements[i].Usage)
|
|
{
|
|
decl.texCoordOffset[vertexElements[i].UsageIndex] = vertexElements[i].Offset;
|
|
decl.texCoordType[vertexElements[i].UsageIndex] = vertexElements[i].Type;
|
|
}
|
|
else if (D3DDECLUSAGE_POSITIONT == vertexElements[i].Usage)
|
|
{
|
|
ve[i].Usage = D3DDECLUSAGE_POSITION;
|
|
decl.isTransformed = true;
|
|
}
|
|
}
|
|
|
|
HRESULT result = m_device.getOrigVtable().pfnCreateVertexShaderDecl(m_device, data, ve.data());
|
|
if (SUCCEEDED(result))
|
|
{
|
|
m_vertexShaderDecls[data->ShaderHandle] = decl;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnDeletePixelShader(HANDLE shader)
|
|
{
|
|
HRESULT result = deleteShader(shader, &State::pixelShader, m_device.getOrigVtable().pfnDeletePixelShader);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
auto it = m_pixelShaders.find(shader);
|
|
if (it != m_pixelShaders.end())
|
|
{
|
|
if (m_pixelShader == &it->second)
|
|
{
|
|
m_pixelShader = nullptr;
|
|
}
|
|
if (it->second.modifiedPixelShader)
|
|
{
|
|
deleteShader(it->second.modifiedPixelShader.release(), &State::pixelShader,
|
|
m_device.getOrigVtable().pfnDeletePixelShader);
|
|
}
|
|
m_pixelShaders.erase(it);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnDeleteVertexShaderDecl(HANDLE shader)
|
|
{
|
|
const bool isCurrent = m_app.vertexShaderDecl == shader;
|
|
HRESULT result = deleteShader(shader, &State::vertexShaderDecl, m_device.getOrigVtable().pfnDeleteVertexShaderDecl);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
if (isCurrent)
|
|
{
|
|
m_vertexDecl = nullptr;
|
|
}
|
|
m_vertexShaderDecls.erase(shader);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnDeleteVertexShaderFunc(HANDLE shader)
|
|
{
|
|
return deleteShader(shader, &State::vertexShaderFunc, m_device.getOrigVtable().pfnDeleteVertexShaderFunc);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetDepthStencil(const D3DDDIARG_SETDEPTHSTENCIL* data)
|
|
{
|
|
m_app.depthStencil = *data;
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
m_device.setDepthStencil(data->hZBuffer);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetPixelShader(HANDLE shader)
|
|
{
|
|
m_app.pixelShader = shader;
|
|
m_changedStates |= CS_SHADER;
|
|
auto it = m_pixelShaders.find(shader);
|
|
m_pixelShader = it != m_pixelShaders.end() ? &it->second : nullptr;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetPixelShaderConst(const D3DDDIARG_SETPIXELSHADERCONST* data, const FLOAT* registers)
|
|
{
|
|
return setShaderConst(data, registers, m_pixelShaderConst, m_device.getOrigVtable().pfnSetPixelShaderConst);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetPixelShaderConstB(const D3DDDIARG_SETPIXELSHADERCONSTB* data, const BOOL* registers)
|
|
{
|
|
return setShaderConst(data, registers, m_pixelShaderConstB, m_device.getOrigVtable().pfnSetPixelShaderConstB);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetPixelShaderConstI(const D3DDDIARG_SETPIXELSHADERCONSTI* data, const INT* registers)
|
|
{
|
|
return setShaderConst(data, registers, m_pixelShaderConstI, m_device.getOrigVtable().pfnSetPixelShaderConstI);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetRenderState(const D3DDDIARG_RENDERSTATE* data)
|
|
{
|
|
m_app.renderState[data->State] = data->Value;
|
|
m_changedRenderStates.set(data->State);
|
|
m_changedStates |= CS_RENDER_STATE;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetRenderTarget(const D3DDDIARG_SETRENDERTARGET* data)
|
|
{
|
|
m_app.renderTarget = *data;
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
m_device.setRenderTarget(*data);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetStreamSource(const D3DDDIARG_SETSTREAMSOURCE* data)
|
|
{
|
|
m_app.streamSource = *data;
|
|
m_app.streamSourceUm = {};
|
|
m_app.streamSourceUmBuffer = nullptr;
|
|
m_changedStates |= CS_STREAM_SOURCE;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM* data, const void* umBuffer)
|
|
{
|
|
m_app.streamSourceUm = *data;
|
|
m_app.streamSourceUmBuffer = umBuffer;
|
|
m_app.streamSource = {};
|
|
m_changedStates |= CS_STREAM_SOURCE;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetTexture(UINT stage, HANDLE texture)
|
|
{
|
|
m_app.textures[stage] = texture;
|
|
m_changedStates |= CS_RENDER_STATE | CS_TEXTURE_STAGE;
|
|
m_changedRenderStates.set(D3DDDIRS_COLORKEYENABLE);
|
|
m_changedTextureStageStates[stage].set(D3DDDITSS_ADDRESSU);
|
|
m_changedTextureStageStates[stage].set(D3DDDITSS_ADDRESSV);
|
|
m_maxChangedTextureStage = std::max(stage, m_maxChangedTextureStage);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetTextureStageState(const D3DDDIARG_TEXTURESTAGESTATE* data)
|
|
{
|
|
if (D3DTSS_ADDRESS == data->State)
|
|
{
|
|
m_app.textureStageState[data->Stage][D3DDDITSS_ADDRESSU] = data->Value;
|
|
m_app.textureStageState[data->Stage][D3DDDITSS_ADDRESSV] = data->Value;
|
|
m_changedTextureStageStates[data->Stage].set(D3DDDITSS_ADDRESSU);
|
|
m_changedTextureStageStates[data->Stage].set(D3DDDITSS_ADDRESSV);
|
|
m_maxChangedTextureStage = std::max(data->Stage, m_maxChangedTextureStage);
|
|
return S_OK;
|
|
}
|
|
|
|
if (D3DDDITSS_TEXTURECOLORKEYVAL == data->State ||
|
|
D3DDDITSS_DISABLETEXTURECOLORKEY == data->State)
|
|
{
|
|
if (D3DDDITSS_TEXTURECOLORKEYVAL == data->State)
|
|
{
|
|
m_app.textureStageState[data->Stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = FALSE;
|
|
}
|
|
m_changedRenderStates.set(D3DDDIRS_COLORKEYENABLE);
|
|
m_changedStates |= CS_RENDER_STATE;
|
|
}
|
|
|
|
m_app.textureStageState[data->Stage][data->State] = data->Value;
|
|
m_changedTextureStageStates[data->Stage].set(data->State);
|
|
m_maxChangedTextureStage = std::max(data->Stage, m_maxChangedTextureStage);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetVertexShaderConst(const D3DDDIARG_SETVERTEXSHADERCONST* data, const void* registers)
|
|
{
|
|
return setShaderConst(data, registers, m_vertexShaderConst, m_device.getOrigVtable().pfnSetVertexShaderConst);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetVertexShaderConstB(const D3DDDIARG_SETVERTEXSHADERCONSTB* data, const BOOL* registers)
|
|
{
|
|
return setShaderConst(data, registers, m_vertexShaderConstB, m_device.getOrigVtable().pfnSetVertexShaderConstB);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetVertexShaderConstI(const D3DDDIARG_SETVERTEXSHADERCONSTI* data, const INT* registers)
|
|
{
|
|
return setShaderConst(data, registers, m_vertexShaderConstI, m_device.getOrigVtable().pfnSetVertexShaderConstI);
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetVertexShaderDecl(HANDLE shader)
|
|
{
|
|
m_app.vertexShaderDecl = shader;
|
|
m_changedStates |= CS_SHADER;
|
|
auto it = m_vertexShaderDecls.find(shader);
|
|
m_vertexDecl = it != m_vertexShaderDecls.end() ? &it->second : nullptr;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetVertexShaderFunc(HANDLE shader)
|
|
{
|
|
m_app.vertexShaderFunc = shader;
|
|
m_changedStates |= CS_SHADER;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetViewport(const D3DDDIARG_VIEWPORTINFO* data)
|
|
{
|
|
m_app.viewport = *data;
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnSetZRange(const D3DDDIARG_ZRANGE* data)
|
|
{
|
|
m_app.zRange = *data;
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DeviceState::pfnUpdateWInfo(const D3DDDIARG_WINFO* data)
|
|
{
|
|
m_app.wInfo = *data;
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
return S_OK;
|
|
}
|
|
|
|
void DeviceState::prepareTextures()
|
|
{
|
|
UINT textureStageCount = getTextureStageCount();
|
|
for (UINT stage = 0; stage < textureStageCount; ++stage)
|
|
{
|
|
auto resource = getTextureResource(stage);
|
|
if (resource)
|
|
{
|
|
resource->updatePalettizedTexture(stage);
|
|
resource->prepareForTextureRead(stage);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Data>
|
|
void DeviceState::removeResource(HANDLE resource, Data State::* data, HANDLE Data::* resourceMember,
|
|
HRESULT(DeviceState::* pfnSetResourceFunc)(const Data*))
|
|
{
|
|
if (resource == m_current.*data.*resourceMember)
|
|
{
|
|
m_current.*data = {};
|
|
m_current.*data.*resourceMember = DELETED_RESOURCE;
|
|
}
|
|
if (resource == m_app.*data.*resourceMember)
|
|
{
|
|
m_app.*data = {};
|
|
(this->*pfnSetResourceFunc)(&(m_app.*data));
|
|
}
|
|
}
|
|
|
|
template <typename Data>
|
|
bool DeviceState::setData(const Data& data, Data& currentData, HRESULT(APIENTRY* origSetData)(HANDLE, const Data*))
|
|
{
|
|
if (0 == memcmp(&data, ¤tData, sizeof(data)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_device.flushPrimitives();
|
|
origSetData(m_device, &data);
|
|
currentData = data;
|
|
return true;
|
|
}
|
|
|
|
void DeviceState::setDepthStencil(const D3DDDIARG_SETDEPTHSTENCIL& depthStencil)
|
|
{
|
|
if (setData(depthStencil, m_current.depthStencil, m_device.getOrigVtable().pfnSetDepthStencil))
|
|
{
|
|
LOG_DS << depthStencil;
|
|
}
|
|
}
|
|
|
|
void DeviceState::setPixelShader(HANDLE shader)
|
|
{
|
|
if (setShader(shader, m_current.pixelShader, m_device.getOrigVtable().pfnSetPixelShader))
|
|
{
|
|
LOG_DS << shader;
|
|
}
|
|
}
|
|
|
|
void DeviceState::setRenderState(const D3DDDIARG_RENDERSTATE& renderState)
|
|
{
|
|
if (renderState.Value == m_current.renderState[renderState.State])
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_device.flushPrimitives();
|
|
m_device.getOrigVtable().pfnSetRenderState(m_device, &renderState);
|
|
m_current.renderState[renderState.State] = renderState.Value;
|
|
LOG_DS << renderState;
|
|
}
|
|
|
|
void DeviceState::setRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget)
|
|
{
|
|
m_device.flushPrimitives();
|
|
m_device.getOrigVtable().pfnSetRenderTarget(m_device, &renderTarget);
|
|
m_current.renderTarget = renderTarget;
|
|
m_current.pixelShader = DELETED_RESOURCE;
|
|
m_current.vertexShaderDecl = DELETED_RESOURCE;
|
|
m_current.vertexShaderFunc = DELETED_RESOURCE;
|
|
m_changedStates |= CS_SHADER;
|
|
LOG_DS << renderTarget;
|
|
}
|
|
|
|
bool DeviceState::setShader(HANDLE shader, HANDLE& currentShader,
|
|
HRESULT(APIENTRY* origSetShaderFunc)(HANDLE, HANDLE))
|
|
{
|
|
if (shader == currentShader)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_device.flushPrimitives();
|
|
origSetShaderFunc(m_device, shader);
|
|
currentShader = shader;
|
|
return true;
|
|
}
|
|
|
|
void DeviceState::setSpriteMode(bool spriteMode)
|
|
{
|
|
if (spriteMode != m_spriteMode)
|
|
{
|
|
m_spriteMode = spriteMode;
|
|
m_changedStates |= CS_RENDER_STATE | CS_TEXTURE_STAGE;
|
|
m_changedRenderStates.set(D3DDDIRS_MULTISAMPLEANTIALIAS);
|
|
if (Config::Settings::SpriteTexCoord::ROUND == Config::spriteTexCoord.get())
|
|
{
|
|
m_changedTextureStageStates[0].set(D3DDDITSS_ADDRESSU);
|
|
m_changedTextureStageStates[0].set(D3DDDITSS_ADDRESSV);
|
|
}
|
|
m_changedTextureStageStates[0].set(D3DDDITSS_MAGFILTER);
|
|
m_changedTextureStageStates[0].set(D3DDDITSS_MINFILTER);
|
|
|
|
D3DDDIARG_SETVERTEXSHADERCONSTB data = {};
|
|
data.Register = 15;
|
|
data.Count = 1;
|
|
BOOL value = spriteMode && Config::Settings::SpriteTexCoord::ROUND == Config::spriteTexCoord.get();
|
|
pfnSetVertexShaderConstB(&data, &value);
|
|
}
|
|
}
|
|
|
|
void DeviceState::setStreamSource(const D3DDDIARG_SETSTREAMSOURCE& streamSource)
|
|
{
|
|
if (0 == memcmp(&streamSource, &m_current.streamSource, sizeof(streamSource)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_device.getDrawPrimitive().setStreamSource(m_app.streamSource);
|
|
m_current.streamSource = streamSource;
|
|
m_current.streamSourceUm = {};
|
|
m_current.streamSourceUmBuffer = nullptr;
|
|
LOG_DS << streamSource;
|
|
}
|
|
|
|
void DeviceState::setStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& streamSourceUm, const void* umBuffer)
|
|
{
|
|
if (umBuffer == m_current.streamSourceUmBuffer &&
|
|
0 == memcmp(&streamSourceUm, &m_current.streamSourceUm, sizeof(streamSourceUm)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_device.getDrawPrimitive().setStreamSourceUm(streamSourceUm, umBuffer);
|
|
m_current.streamSource = {};
|
|
m_current.streamSourceUm = streamSourceUm;
|
|
m_current.streamSourceUmBuffer = umBuffer;
|
|
LOG_DS << streamSourceUm << " " << umBuffer;
|
|
}
|
|
|
|
void DeviceState::setTempDepthStencil(const D3DDDIARG_SETDEPTHSTENCIL& depthStencil)
|
|
{
|
|
setDepthStencil(depthStencil);
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
}
|
|
|
|
void DeviceState::setTempPixelShader(HANDLE shader)
|
|
{
|
|
setPixelShader(shader);
|
|
m_changedStates |= CS_SHADER;
|
|
}
|
|
|
|
void DeviceState::setTempRenderState(const D3DDDIARG_RENDERSTATE& renderState)
|
|
{
|
|
setRenderState(renderState);
|
|
m_changedStates |= CS_RENDER_STATE;
|
|
m_changedRenderStates.set(renderState.State);
|
|
}
|
|
|
|
void DeviceState::setTempRenderTarget(const D3DDDIARG_SETRENDERTARGET& renderTarget)
|
|
{
|
|
setRenderTarget(renderTarget);
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
}
|
|
|
|
void DeviceState::setTempStreamSource(const D3DDDIARG_SETSTREAMSOURCE& streamSource)
|
|
{
|
|
setStreamSource(streamSource);
|
|
m_changedStates |= CS_STREAM_SOURCE;
|
|
}
|
|
|
|
void DeviceState::setTempStreamSourceUm(const D3DDDIARG_SETSTREAMSOURCEUM& streamSourceUm, const void* umBuffer)
|
|
{
|
|
setStreamSourceUm(streamSourceUm, umBuffer);
|
|
m_changedStates |= CS_STREAM_SOURCE;
|
|
}
|
|
|
|
void DeviceState::setTempTexture(UINT stage, HANDLE texture)
|
|
{
|
|
setTexture(stage, texture);
|
|
m_changedStates |= CS_TEXTURE_STAGE;
|
|
m_maxChangedTextureStage = std::max(stage, m_maxChangedTextureStage);
|
|
}
|
|
|
|
void DeviceState::setTempTextureStageState(const D3DDDIARG_TEXTURESTAGESTATE& tss)
|
|
{
|
|
setTextureStageState(tss);
|
|
m_changedStates |= CS_TEXTURE_STAGE;
|
|
m_changedTextureStageStates[tss.Stage].set(tss.State);
|
|
m_maxChangedTextureStage = std::max(tss.Stage, m_maxChangedTextureStage);
|
|
}
|
|
|
|
void DeviceState::setTempVertexShaderDecl(HANDLE decl)
|
|
{
|
|
setVertexShaderDecl(decl);
|
|
m_changedStates |= CS_SHADER;
|
|
}
|
|
|
|
void DeviceState::setTempViewport(const D3DDDIARG_VIEWPORTINFO& viewport)
|
|
{
|
|
setViewport(viewport);
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
}
|
|
|
|
void DeviceState::setTempWInfo(const D3DDDIARG_WINFO& wInfo)
|
|
{
|
|
setWInfo(wInfo);
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
}
|
|
|
|
void DeviceState::setTempZRange(const D3DDDIARG_ZRANGE& zRange)
|
|
{
|
|
setZRange(zRange);
|
|
m_changedStates |= CS_RENDER_TARGET;
|
|
}
|
|
|
|
bool DeviceState::setTexture(UINT stage, HANDLE texture)
|
|
{
|
|
if (texture == m_current.textures[stage])
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_device.flushPrimitives();
|
|
m_device.getOrigVtable().pfnSetTexture(m_device, stage, texture);
|
|
m_current.textures[stage] = texture;
|
|
|
|
if (0 == stage && texture)
|
|
{
|
|
auto resource = (texture == m_app.textures[stage]) ? getTextureResource(stage) : m_device.getResource(texture);
|
|
if (resource)
|
|
{
|
|
D3DDDIARG_SETVERTEXSHADERCONST data = {};
|
|
data.Register = 253;
|
|
data.Count = 1;
|
|
|
|
auto& si = resource->getFixedDesc().pSurfList[0];
|
|
ShaderConstF reg = { static_cast<float>(si.Width), static_cast<float>(si.Height),
|
|
m_vertexShaderConst[253][2], m_vertexShaderConst[253][3] };
|
|
|
|
if (0 != memcmp(®, &m_vertexShaderConst[data.Register], sizeof(reg)))
|
|
{
|
|
pfnSetVertexShaderConst(&data, ®);
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_DS << stage << " " << texture;
|
|
return true;
|
|
}
|
|
|
|
void DeviceState::setTextureStageState(const D3DDDIARG_TEXTURESTAGESTATE& tss)
|
|
{
|
|
if (tss.Value == m_current.textureStageState[tss.Stage][tss.State])
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_device.flushPrimitives();
|
|
m_device.getOrigVtable().pfnSetTextureStageState(m_device, &tss);
|
|
m_current.textureStageState[tss.Stage][tss.State] = tss.Value;
|
|
LOG_DS << tss;
|
|
}
|
|
|
|
void DeviceState::setVertexShaderDecl(HANDLE decl)
|
|
{
|
|
if (setShader(decl, m_current.vertexShaderDecl, m_device.getOrigVtable().pfnSetVertexShaderDecl))
|
|
{
|
|
LOG_DS << decl;
|
|
}
|
|
}
|
|
|
|
void DeviceState::setVertexShaderFunc(HANDLE shader)
|
|
{
|
|
if (setShader(shader, m_current.vertexShaderFunc, m_device.getOrigVtable().pfnSetVertexShaderFunc))
|
|
{
|
|
LOG_DS << shader;
|
|
}
|
|
}
|
|
|
|
bool DeviceState::setViewport(const D3DDDIARG_VIEWPORTINFO& viewport)
|
|
{
|
|
if (setData(viewport, m_current.viewport, m_device.getOrigVtable().pfnSetViewport))
|
|
{
|
|
LOG_DS << viewport;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DeviceState::setWInfo(const D3DDDIARG_WINFO& wInfo)
|
|
{
|
|
if (setData(wInfo, m_current.wInfo, m_device.getOrigVtable().pfnUpdateWInfo))
|
|
{
|
|
LOG_DS << wInfo;
|
|
}
|
|
}
|
|
|
|
bool DeviceState::setZRange(const D3DDDIARG_ZRANGE& zRange)
|
|
{
|
|
if (setData(zRange, m_current.zRange, m_device.getOrigVtable().pfnSetZRange))
|
|
{
|
|
LOG_DS << zRange;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <typename SetShaderConstData, typename ShaderConstArray, typename Register>
|
|
HRESULT DeviceState::setShaderConst(const SetShaderConstData* data, const Register* registers,
|
|
ShaderConstArray& shaderConstArray,
|
|
HRESULT(APIENTRY* origSetShaderConstFunc)(HANDLE, const SetShaderConstData*, const Register*))
|
|
{
|
|
m_device.flushPrimitives();
|
|
HRESULT result = origSetShaderConstFunc(m_device, data, registers);
|
|
if (SUCCEEDED(result))
|
|
{
|
|
memcpy(&shaderConstArray[data->Register], registers, data->Count * sizeof(ShaderConstArray::value_type));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void DeviceState::updateConfig()
|
|
{
|
|
m_changedStates |= CS_RENDER_STATE | CS_RENDER_TARGET | CS_SHADER | CS_TEXTURE_STAGE;
|
|
m_changedRenderStates.set(D3DDDIRS_COLORKEYENABLE);
|
|
m_changedRenderStates.set(D3DDDIRS_MULTISAMPLEANTIALIAS);
|
|
|
|
for (auto& ps : m_pixelShaders)
|
|
{
|
|
if (ps.second.modifiedPixelShader.get())
|
|
{
|
|
deleteShader(ps.second.modifiedPixelShader.release(), &State::pixelShader,
|
|
m_device.getOrigVtable().pfnDeletePixelShader);
|
|
}
|
|
ps.second.isModified = false;
|
|
}
|
|
|
|
for (UINT i = 0; i < m_changedTextureStageStates.size(); ++i)
|
|
{
|
|
m_changedTextureStageStates[i].set(D3DDDITSS_MINFILTER);
|
|
m_changedTextureStageStates[i].set(D3DDDITSS_MAGFILTER);
|
|
m_changedTextureStageStates[i].set(D3DDDITSS_MIPFILTER);
|
|
m_changedTextureStageStates[i].set(D3DDDITSS_MAXANISOTROPY);
|
|
m_changedTextureStageStates[i].set(D3DDDITSS_TEXTURECOLORKEYVAL);
|
|
}
|
|
m_changedTextureStageStates[0].set(D3DDDITSS_ADDRESSU);
|
|
m_changedTextureStageStates[0].set(D3DDDITSS_ADDRESSV);
|
|
m_maxChangedTextureStage = m_changedTextureStageStates.size() - 1;
|
|
}
|
|
|
|
void DeviceState::updateRenderStates()
|
|
{
|
|
m_changedRenderStates.forEach([&](UINT stateIndex)
|
|
{
|
|
const auto state = static_cast<D3DDDIRENDERSTATETYPE>(stateIndex);
|
|
setRenderState({ state, mapRsValue(state, m_app.renderState[state]) });
|
|
});
|
|
m_changedRenderStates.reset();
|
|
}
|
|
|
|
void DeviceState::updateRenderTarget()
|
|
{
|
|
auto vp = m_app.viewport;
|
|
auto renderTarget = m_app.renderTarget;
|
|
auto depthStencil = m_app.depthStencil;
|
|
|
|
Resource* resource = m_device.getResource(renderTarget.hRenderTarget);
|
|
if (resource && resource->getCustomResource())
|
|
{
|
|
resource->scaleRect(reinterpret_cast<RECT&>(vp));
|
|
renderTarget.hRenderTarget = *resource->getCustomResource();
|
|
}
|
|
|
|
resource = m_device.getResource(depthStencil.hZBuffer);
|
|
if (resource && resource->getCustomResource())
|
|
{
|
|
depthStencil.hZBuffer = *resource->getCustomResource();
|
|
}
|
|
|
|
setRenderTarget(renderTarget);
|
|
setDepthStencil(depthStencil);
|
|
setViewport(vp);
|
|
|
|
auto wInfo = m_app.wInfo;
|
|
if (1.0f == wInfo.WNear && 1.0f == wInfo.WFar)
|
|
{
|
|
wInfo.WNear = 0.0f;
|
|
}
|
|
setWInfo(wInfo);
|
|
|
|
setZRange(m_app.zRange);
|
|
|
|
updateVertexFixupConstants();
|
|
}
|
|
|
|
void DeviceState::updateShaders()
|
|
{
|
|
setPixelShader(mapPixelShader(m_app.pixelShader));
|
|
setVertexShaderDecl(m_app.vertexShaderDecl);
|
|
auto it = m_vertexShaderDecls.find(m_app.vertexShaderDecl);
|
|
if (it != m_vertexShaderDecls.end() && it->second.isTransformed)
|
|
{
|
|
setVertexShaderFunc(m_vsVertexFixup.get());
|
|
}
|
|
else
|
|
{
|
|
setVertexShaderFunc(m_app.vertexShaderFunc);
|
|
}
|
|
}
|
|
|
|
void DeviceState::updateStreamSource()
|
|
{
|
|
if (m_app.streamSource.hVertexBuffer)
|
|
{
|
|
setStreamSource(m_app.streamSource);
|
|
}
|
|
else if (m_app.streamSourceUmBuffer)
|
|
{
|
|
setStreamSourceUm(m_app.streamSourceUm, m_app.streamSourceUmBuffer);
|
|
}
|
|
}
|
|
|
|
void DeviceState::updateTextureColorKey(UINT stage)
|
|
{
|
|
m_changedTextureStageStates[stage].reset(D3DDDITSS_DISABLETEXTURECOLORKEY);
|
|
m_changedTextureStageStates[stage].reset(D3DDDITSS_TEXTURECOLORKEYVAL);
|
|
if (!m_app.textures[stage] || Config::Settings::ColorKeyMethod::NONE == Config::colorKeyMethod.get())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Config::Settings::ColorKeyMethod::ALPHATEST == Config::colorKeyMethod.get())
|
|
{
|
|
const BOOL colorKeyEnabled = !m_app.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY];
|
|
if (colorKeyEnabled != m_pixelShaderConstB[stage][0])
|
|
{
|
|
D3DDDIARG_SETPIXELSHADERCONSTB data = {};
|
|
data.Register = stage;
|
|
data.Count = 1;
|
|
setShaderConst(&data, &colorKeyEnabled, m_pixelShaderConstB, m_device.getOrigVtable().pfnSetPixelShaderConstB);
|
|
}
|
|
return;
|
|
}
|
|
|
|
D3DDDIARG_TEXTURESTAGESTATE tss = {};
|
|
tss.Stage = stage;
|
|
|
|
if (m_app.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY])
|
|
{
|
|
tss.State = D3DDDITSS_DISABLETEXTURECOLORKEY;
|
|
tss.Value = m_app.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY];
|
|
m_current.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = tss.Value;
|
|
}
|
|
else
|
|
{
|
|
tss.State = D3DDDITSS_TEXTURECOLORKEYVAL;
|
|
tss.Value = m_app.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL];
|
|
auto resource = getTextureResource(stage);
|
|
if (resource && resource->getPalettizedTexture())
|
|
{
|
|
tss.Value = reinterpret_cast<DWORD&>(
|
|
m_device.getPalette(resource->getPalettizedTexture()->getPaletteHandle())[tss.Value]) & 0xFFFFFF;
|
|
}
|
|
m_current.textureStageState[stage][D3DDDITSS_TEXTURECOLORKEYVAL] = tss.Value;
|
|
m_current.textureStageState[stage][D3DDDITSS_DISABLETEXTURECOLORKEY] = FALSE;
|
|
}
|
|
|
|
m_device.flushPrimitives();
|
|
m_device.getOrigVtable().pfnSetTextureStageState(m_device, &tss);
|
|
LOG_DS << tss;
|
|
}
|
|
|
|
void DeviceState::updateTextureStages()
|
|
{
|
|
for (UINT stage = 0; stage <= m_maxChangedTextureStage; ++stage)
|
|
{
|
|
auto resource = getTextureResource(stage);
|
|
if (resource)
|
|
{
|
|
resource = &resource->prepareForTextureRead(stage);
|
|
}
|
|
|
|
if (setTexture(stage, resource ? *resource : m_app.textures[stage]) ||
|
|
m_changedTextureStageStates[stage].test(D3DDDITSS_DISABLETEXTURECOLORKEY) ||
|
|
m_changedTextureStageStates[stage].test(D3DDDITSS_TEXTURECOLORKEYVAL))
|
|
{
|
|
updateTextureColorKey(stage);
|
|
}
|
|
|
|
m_changedTextureStageStates[stage].forEach([&](UINT stateIndex)
|
|
{
|
|
const auto state = static_cast<D3DDDITEXTURESTAGESTATETYPE>(stateIndex);
|
|
setTextureStageState({ stage, state, mapTssValue(stage, state, m_app.textureStageState[stage][state]) });
|
|
});
|
|
m_changedTextureStageStates[stage].reset();
|
|
}
|
|
}
|
|
|
|
void DeviceState::updateVertexFixupConstants()
|
|
{
|
|
D3DDDIARG_SETVERTEXSHADERCONST data = {};
|
|
data.Register = 253;
|
|
data.Count = 3;
|
|
|
|
const float stc = static_cast<float>(Config::spriteTexCoord.getParam()) / 100;
|
|
const float apc = Config::alternatePixelCenter.get();
|
|
const auto& vp = m_app.viewport;
|
|
const auto& zr = m_current.zRange;
|
|
const float sx = static_cast<float>(m_current.viewport.Width) / m_app.viewport.Width;
|
|
const float sy = static_cast<float>(m_current.viewport.Height) / m_app.viewport.Height;
|
|
|
|
ShaderConstF registers[3] = {
|
|
{ m_vertexShaderConst[253][0], m_vertexShaderConst[253][1], stc, stc },
|
|
{ 0.5f + apc - 0.5f / sx - vp.X - vp.Width / 2, 0.5f + apc - 0.5f / sy - vp.Y - vp.Height / 2, -zr.MinZ, 0.0f },
|
|
{ 2.0f / vp.Width, -2.0f / vp.Height, 1.0f / (zr.MaxZ - zr.MinZ), 1.0f }
|
|
};
|
|
|
|
if (0 != memcmp(registers, &m_vertexShaderConst[data.Register], sizeof(registers)))
|
|
{
|
|
pfnSetVertexShaderConst(&data, registers);
|
|
}
|
|
}
|
|
}
|