赞
踩
这次主要吧鼠标绘制出来,废了老劲了...
首先需要设置混合模式,不然鼠标的透明部分会呈现出纯黑色,不能直接将鼠标数据复制到抓取的桌面纹理中。
- // 透明
- ID3D11BlendState* blendState;
- D3D11_BLEND_DESC blendDesc = {};
- blendDesc.AlphaToCoverageEnable = FALSE;
- blendDesc.IndependentBlendEnable = FALSE;
- blendDesc.RenderTarget->BlendEnable = TRUE; // 是否开启混合
- blendDesc.RenderTarget->SrcBlend = D3D11_BLEND_SRC_ALPHA; // 将源图的 alpha 作为 src rgb 的混合因子
- blendDesc.RenderTarget->DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // 将源图的 1-alpha 作为 dst rgb 的混合因子
- blendDesc.RenderTarget->BlendOp = D3D11_BLEND_OP_ADD; // 进行相加操作
- blendDesc.RenderTarget->SrcBlendAlpha = D3D11_BLEND_ONE; //
- blendDesc.RenderTarget->DestBlendAlpha = D3D11_BLEND_ONE;
- blendDesc.RenderTarget->BlendOpAlpha = D3D11_BLEND_OP_ADD;
- blendDesc.RenderTarget->RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; // 可以写入的位置
- this->m_device->CreateBlendState(&blendDesc, &blendState);
- const FLOAT BlendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
- this->m_context->OMSetBlendState(blendState, BlendFactor, 0xffffffff);
- SAFE_RELEASE(blendState);
以上是设置混合模式的代码,主要是将鼠标的透明部分正确显示。
需要将鼠标数据读取为单独的纹理,也就是每次渲染两个纹理视图,因此优化了渲染结构。
将所有可绑定到管线的组件统一封装,提供出接口。
- class BindAbleInterface {
- public:
- BindAbleInterface() = default;
- virtual void bind(ID3D11DeviceContext* _context) = 0;
- virtual ~BindAbleInterface() = default;
- };
-
- class IndexBufferBindAble : public BindAbleInterface {
- public:
- IndexBufferBindAble(ID3D11Device* _device, const UINT16* _indices, size_t _indicesSize);
- void bind(ID3D11DeviceContext* _context) override;
- ~IndexBufferBindAble() override;
- private:
- Microsoft::WRL::ComPtr<ID3D11Buffer> m_buffer = nullptr;
- };
-
- class VertexScalBufferBindAble: public BindAbleInterface {
- public:
- __declspec(align(16)) struct {
- __declspec(align(16)) struct {
- float x;
- float y;
- float z;
- } Scal;
- __declspec(align(16)) struct {
- float x;
- float y;
- } Translation;
- } m_psConstant;
-
- VertexScalBufferBindAble(ID3D11Device* _device, float _x_rate, float _y_rate, float _z_rate, float _x, float _y);
- void bind(ID3D11DeviceContext* _context) override;
- void changeTranslation(ID3D11DeviceContext* _context, float _x, float _y);
- ~VertexScalBufferBindAble();
- private:
- Microsoft::WRL::ComPtr<ID3D11Buffer> m_ps_constant_buffer = nullptr;
- };
-
-
- void VertexScalBufferBindAble::bind(ID3D11DeviceContext* _context)
- {
- _context->VSSetConstantBuffers(0, 1, this->m_ps_constant_buffer.GetAddressOf());
- }
-
- void VertexScalBufferBindAble::changeTranslation(ID3D11DeviceContext* _context, float _x, float _y)
- {
- m_psConstant.Translation.x = _x;
- m_psConstant.Translation.y = _y;
- D3D11_MAPPED_SUBRESOURCE mapped_resource;
- _context->Map(this->m_ps_constant_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource);
- memcpy(mapped_resource.pData, (void*)&m_psConstant, sizeof(m_psConstant));
- _context->Unmap(this->m_ps_constant_buffer.Get(), 0);
- }
-
- VertexScalBufferBindAble::~VertexScalBufferBindAble()
- {
- }
以上是VertexScalBufferBindAble的例子,给出缩放和平移矩阵,主要给鼠标纹理进行缩放和平移。
修改VertexShader,将变换矩阵乘进去
- struct VSOut
- {
- float2 tex: TEXCOORD;
- float4 pos : SV_POSITION;
- };
-
- struct Scal {
- float x;
- float y;
- float z;
- };
-
- struct Translation {
- float x;
- float y;
- };
-
- cbuffer Cbuf {
- Scal scal;
- Translation translation;
- };
-
- VSOut main_VS(float3 pos : POSITION, float2 tex : TEXCOORD)
- {
- VSOut vsout;
- vsout.pos = float4((pos.x * scal.x) + translation.x, (pos.y * scal.y) + translation.y, pos.z * scal.z, 1);
- vsout.tex = tex;
- return vsout;
- }
接下来,绘制鼠标,其它逻辑详细可以看源码,这里说一下怎么将鼠标转为纹理
- void CursorTextureDrawAble::drawCursor(MyDx11* _myDx11)
- {
- CURSORINFO ci = { 0 };
- ci.cbSize = sizeof(ci);
- if (!GetCursorInfo(&ci)) {
- return;
- }
- float offset_x = ci.ptScreenPos.x / this->m_base_x;
- float offset_y = ci.ptScreenPos.y / this->m_base_y;
- offset_x = offset_x * 2 - 1;
- offset_y = 1 - offset_y * 2;
- this->m_vertex_scal_buffer->changeTranslation(this->getContext(_myDx11), offset_x, offset_y);
- if (this->m_cache_cursor == nullptr || this->m_cache_cursor != ci.hCursor) {
- this->m_cache_cursor = ci.hCursor;
- }
- else {
- return;
- }
- }
缓存一下已经获取的鼠标句柄,如果没有变化就不需要更改纹理数据了,算一下鼠标的相对位置进行平移变换。
- bool CursorTextureDrawAble::copyFromColor(MyDx11* _myDx11, ICONINFO& _icon_info, BITMAP& _bmp)
- {
- uint8_t* output = nullptr;
- if (GetObject(_icon_info.hbmColor, sizeof(_bmp), &_bmp) == 0) {
- return false;
- }
- unsigned int size = _bmp.bmHeight * _bmp.bmWidthBytes;
- output = new uint8_t[size];
- GetBitmapBits(_icon_info.hbmColor, size, output);
- if (_bmp.bmWidth != this->m_width && _bmp.bmHeight != this->m_height) {
- this->changeSize(_myDx11, _bmp.bmWidth, _bmp.bmHeight, false);
- }
- this->copyData(_myDx11, output, size);
- delete[] output;
- return true;
- }
-
- bool CursorTextureDrawAble::copyFromMask(MyDx11* _myDx11, ICONINFO& _icon_info, BITMAP& _bmp)
- {
- long pixels;
- long bottom;
- uint8_t pix_byte;
- bool alpha = false;
- if (GetObject(_icon_info.hbmMask, sizeof(_bmp), &_bmp) == 0) {
- return false;
- }
- uint8_t* output;
- uint8_t* mask;
- unsigned int size = _bmp.bmHeight * _bmp.bmWidthBytes;
- mask = new uint8_t[size];
- GetBitmapBits(_icon_info.hbmMask, size, mask);
- _bmp.bmHeight /= 2;
- pixels = _bmp.bmHeight * _bmp.bmWidth;
- output = new uint8_t[pixels * 4];
- ZeroMemory(output, pixels * 4);
- bottom = _bmp.bmWidthBytes * _bmp.bmHeight;
- for (long i = 0; i < pixels; i++) {
- uint8_t andMask = this->bitToAlpha(mask, i);
- uint8_t xorMask = this->bitToAlpha(mask + bottom, i);
- if (!andMask) {
- // black in the AND mask
- *(uint32_t*)&output[i * 4] =
- !!xorMask ? 0x00FFFFFF /*always white*/
- : 0xFF000000 /*always black*/;
- }
- else {
- // white in the AND mask
- *(uint32_t*)&output[i * 4] =
- !!xorMask ? 0xFFFFFFFF /*source inverted*/
- : 0 /*transparent*/;
- }
- }
- if (_bmp.bmWidth != this->m_width && _bmp.bmHeight != this->m_height) {
- this->changeSize(_myDx11, _bmp.bmWidth, _bmp.bmHeight, false);
- }
- this->copyData(_myDx11, output, pixels * 4);
- delete[] output;
- delete[] mask;
- return true;
- }
-
- uint8_t CursorTextureDrawAble::bitToAlpha(uint8_t* data, long pixel)
- {
- uint8_t pix_byte = data[pixel / 8];
- bool alpha = (pix_byte >> (7 - pixel % 8) & 1) != 0;
- return alpha ? 0xFF : 0;
- }
-
- void TextureDrawAble::copyData(MyDx11* _myDx11, uint8_t* _buffer, size_t _size)
- {
- D3D11_MAPPED_SUBRESOURCE target_map_res;
- UINT sub_resource = D3D11CalcSubresource(0, 0, 0);
- ID3D11DeviceContext* context = this->getContext(_myDx11);
- HRESULT hr = context->Map(this->m_texture.Get(), sub_resource, D3D11_MAP_WRITE_DISCARD, 0, &target_map_res);
- if (FAILED(hr)) {
- return;
- }
- memcpy_s(target_map_res.pData, _size, _buffer, _size);
- context->Unmap(this->m_texture.Get(), sub_resource);
- }
以上是通过鼠标句柄获取到bitmap,再copy到纹理中,参考了obs源码。之前提到当鼠标处于选中文字形状,也就是类似I的形状时获取不到鼠标。其原因在于需要从hbmMask中获取数据。里面的处理逻辑看不太明白,直接拿的obs的源码。
关于编码器性能问题,设置编码线程数可以解决部分问题,但性能依旧不太高。
this->m_encode_pCodecCtx->thread_count = 4;
如果实在不行,考虑使用硬编码方式。
具体详情转到源码。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。