std::shared_ptr DGSLEffectFactory::Impl::CreateDGSLEffect()

in Src/DGSLEffectFactory.cpp [171:368]


std::shared_ptr<IEffect> DGSLEffectFactory::Impl::CreateDGSLEffect(DGSLEffectFactory* factory, const DGSLEffectFactory::DGSLEffectInfo& info, ID3D11DeviceContext* deviceContext)
{
    if (mSharing && info.name && *info.name)
    {
        if (info.enableSkinning)
        {
            auto it = mEffectCacheSkinning.find(info.name);
            if (it != mEffectCacheSkinning.end())
            {
                return it->second;
            }
        }
        else
        {
            auto it = mEffectCache.find(info.name);
            if (it != mEffectCache.end())
            {
                return it->second;
            }
        }
    }

    std::shared_ptr<DGSLEffect> effect;

    bool lighting = true;
    bool allowSpecular = true;

    if (!info.pixelShader || !*info.pixelShader)
    {
        if (info.enableSkinning)
        {
            effect = std::make_shared<SkinnedDGSLEffect>(mDevice.Get(), nullptr);
        }
        else
        {
            effect = std::make_shared<DGSLEffect>(mDevice.Get(), nullptr);
        }
    }
    else
    {
        wchar_t root[MAX_PATH] = {};
        auto last = wcsrchr(info.pixelShader, '_');
        if (last)
        {
            wcscpy_s(root, last + 1);
        }
        else
        {
            wcscpy_s(root, info.pixelShader);
        }

        auto first = wcschr(root, '.');
        if (first)
            *first = 0;

        ComPtr<ID3D11PixelShader> ps;
        if (!_wcsicmp(root, L"lambert"))
        {
            allowSpecular = false;
        }
        else if (!_wcsicmp(root, L"phong"))
        {
            // lighting, allowSpecular = true
        }
        else if (!_wcsicmp(root, L"unlit"))
        {
            lighting = false;
        }
        else if (mDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
        {
            // DGSL shaders are not compatible with Feature Level 9.x, use fallback shader
            wcscat_s(root, L".cso");

            factory->CreatePixelShader(root, ps.GetAddressOf());
        }
        else
        {
            // Create DGSL shader and use it for the effect
            factory->CreatePixelShader(info.pixelShader, ps.GetAddressOf());
        }

        if (info.enableSkinning)
        {
            effect = std::make_shared<SkinnedDGSLEffect>(mDevice.Get(), ps.Get());
        }
        else
        {
            effect = std::make_shared<DGSLEffect>(mDevice.Get(), ps.Get());
        }
    }

    if (lighting)
    {
        effect->EnableDefaultLighting();
        effect->SetLightingEnabled(true);
    }

    XMVECTOR color = XMLoadFloat3(&info.ambientColor);
    effect->SetAmbientColor(color);

    color = XMLoadFloat3(&info.diffuseColor);
    effect->SetDiffuseColor(color);
    effect->SetAlpha(info.alpha);

    if (info.perVertexColor)
    {
        effect->SetVertexColorEnabled(true);
    }

    effect->SetAlphaDiscardEnable(true);

    if (allowSpecular
        && (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0))
    {
        color = XMLoadFloat3(&info.specularColor);
        effect->SetSpecularColor(color);
        effect->SetSpecularPower(info.specularPower);
    }
    else
    {
        effect->DisableSpecular();
    }

    if (info.emissiveColor.x != 0 || info.emissiveColor.y != 0 || info.emissiveColor.z != 0)
    {
        color = XMLoadFloat3(&info.emissiveColor);
        effect->SetEmissiveColor(color);
    }

    if (info.diffuseTexture && *info.diffuseTexture)
    {
        ComPtr<ID3D11ShaderResourceView> srv;

        factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());

        effect->SetTexture(srv.Get());
        effect->SetTextureEnabled(true);
    }

    if (info.specularTexture && *info.specularTexture)
    {
        ComPtr<ID3D11ShaderResourceView> srv;

        factory->CreateTexture(info.specularTexture, deviceContext, srv.GetAddressOf());

        effect->SetTexture(1, srv.Get());
        effect->SetTextureEnabled(true);
    }

    if (info.normalTexture && *info.normalTexture)
    {
        ComPtr<ID3D11ShaderResourceView> srv;

        factory->CreateTexture(info.normalTexture, deviceContext, srv.GetAddressOf());

        effect->SetTexture(2, srv.Get());
        effect->SetTextureEnabled(true);
    }

    if (info.emissiveTexture && *info.emissiveTexture)
    {
        ComPtr<ID3D11ShaderResourceView> srv;

        factory->CreateTexture(info.emissiveTexture, deviceContext, srv.GetAddressOf());

        effect->SetTexture(3, srv.Get());
        effect->SetTextureEnabled(true);
    }

    for (size_t j = 0; j < std::size(info.textures); ++j)
    {
        if (info.textures[j] && *info.textures[j])
        {
            ComPtr<ID3D11ShaderResourceView> srv;

            factory->CreateTexture(info.textures[j], deviceContext, srv.GetAddressOf());

            effect->SetTexture(static_cast<int>(j) + DGSLEffectInfo::BaseTextureOffset, srv.Get());
            effect->SetTextureEnabled(true);
        }
    }

    if (mSharing && info.name && *info.name)
    {
        std::lock_guard<std::mutex> lock(mutex);
        EffectCache::value_type v(info.name, effect);
        if (info.enableSkinning)
        {
            mEffectCacheSkinning.insert(v);
        }
        else
        {
            mEffectCache.insert(v);
        }
    }

    return std::move(effect);
}