struct D3D11_Texture {
  ID3D11Texture2D* texture;
  ID3D11ShaderResourceView* out_srv;
  s32 out_width;
  s32 out_height;
  bool loaded = false;
};

// Maybe should be part of ImGui_Supplementary?
struct Image_Data {
  u8* data;
  s32 width;
  s32 height;
  s32 depth;
  f32 scale_factor = 1.0;
  D3D11_Texture d3d_texture;
};

// #NOTE: redefined from imgui_impl_dx11.cpp (not supposed to do that?)
struct ImGui_ImplDX11_Data
{
    ID3D11Device*               pd3dDevice;
    ID3D11DeviceContext*        pd3dDeviceContext;
    IDXGIFactory*               pFactory;
    ID3D11Buffer*               pVB;
    ID3D11Buffer*               pIB;
    ID3D11VertexShader*         pVertexShader;
    ID3D11InputLayout*          pInputLayout;
    ID3D11Buffer*               pVertexConstantBuffer;
    ID3D11PixelShader*          pPixelShader;
    ID3D11SamplerState*         pTexSamplerLinear;
    ID3D11RasterizerState*      pRasterizerState;
    ID3D11BlendState*           pBlendState;
    ID3D11DepthStencilState*    pDepthStencilState;
    int                         VertexBufferSize;
    int                         IndexBufferSize;
    ImVector<DXGI_SWAP_CHAIN_DESC> SwapChainDescsForViewports;

    ImGui_ImplDX11_Data()       { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
};

// Also copy-pasted.
static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
{
    return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}

void icon_load_d3d_texture (Image_Data* id) {
  ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
  auto d3d_device = bd->pd3dDevice;
  
  D3D11_TEXTURE2D_DESC desc = {};
  desc.Width = id->width;
  desc.Height = id->height;
  desc.MipLevels = 1;
  desc.ArraySize = 1;
  desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  desc.SampleDesc.Count = 1;
  desc.Usage = D3D11_USAGE_DEFAULT;
  desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; // D3D11_BIND_FLAG
  desc.CPUAccessFlags = 0;
  
  D3D11_SUBRESOURCE_DATA sr = {};
  sr.pSysMem = id->data;
  sr.SysMemPitch = (desc.Width * 4);
  sr.SysMemSlicePitch = 0;
  HRESULT hr = d3d_device->CreateTexture2D(&desc, &sr, &id->d3d_texture.texture);
  if (hr != S_OK) {
    log_error("ID3D11Device_CreateBuffer failed: %d\n", hr);
    os_log_error();
    return;
  }
  
  D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  srvDesc.Format = desc.Format;
  srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
  srvDesc.Texture2D.MipLevels = desc.MipLevels;
  srvDesc.Texture2D.MostDetailedMip = 0;
  hr = d3d_device->CreateShaderResourceView(id->d3d_texture.texture, 
        &srvDesc, &id->d3d_texture.out_srv);
  if (hr != S_OK) {
    log_error("ID3D11Device_CreateShaderResourceView failed: %d\n", hr);
    os_log_error();
    return;
  }
  
  // IUnknown::Release(id->d3d_texture.texture);
  id->d3d_texture.texture->Release();
  id->d3d_texture.texture = nullptr;

  id->d3d_texture.out_width  = id->width;
  id->d3d_texture.out_height = id->height;
  id->d3d_texture.loaded     = true;
}

void delete_d3d_texture (D3D11_Texture* t) {
  if (!t->loaded) return;
  t->out_srv->Release();
  t->loaded = false;
}

#define Get_ImTextureID(x) (ImTextureID)(x->out_srv)

void show_d3d_texture_height (D3D11_Texture* t, f32 new_height) {
  f32 new_scale_factor = new_height / t->out_height;
  f32 new_width = t->out_width * new_scale_factor;
  
  if (t->loaded) {
    ImGui::Image(Get_ImTextureID(t), {new_width, new_height}, {0, 0}, 
      {1, 1}, {1, 1, 1, 1}, {0, 0, 0, 0});
  }
}
