/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "test/win/d3d_renderer.h"

#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "rtc_base/checks.h"

namespace webrtc {
namespace test {

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1)

struct D3dCustomVertex {
  float x, y, z;
  float u, v;
};

const char kD3DClassName[] = "d3d_renderer";

VideoRenderer* VideoRenderer::CreatePlatformRenderer(const char* window_title,
                                                     size_t width,
                                                     size_t height) {
  return D3dRenderer::Create(window_title, width, height);
}

D3dRenderer::D3dRenderer(size_t width, size_t height)
    : width_(width),
      height_(height),
      hwnd_(NULL),
      d3d_(NULL),
      d3d_device_(NULL),
      texture_(NULL),
      vertex_buffer_(NULL) {
  RTC_DCHECK_GT(width, 0);
  RTC_DCHECK_GT(height, 0);
}

D3dRenderer::~D3dRenderer() { Destroy(); }

LRESULT WINAPI D3dRenderer::WindowProc(HWND hwnd, UINT msg, WPARAM wparam,
                                       LPARAM lparam) {
  if (msg == WM_DESTROY || (msg == WM_CHAR && wparam == VK_RETURN)) {
    PostQuitMessage(0);
    return 0;
  }

  return DefWindowProcA(hwnd, msg, wparam, lparam);
}

void D3dRenderer::Destroy() {
  texture_ = NULL;
  vertex_buffer_ = NULL;
  d3d_device_ = NULL;
  d3d_ = NULL;

  if (hwnd_ != NULL) {
    DestroyWindow(hwnd_);
    RTC_DCHECK(!IsWindow(hwnd_));
    hwnd_ = NULL;
  }
}

bool D3dRenderer::Init(const char* window_title) {
  hwnd_ = CreateWindowA(kD3DClassName,
                        window_title,
                        WS_OVERLAPPEDWINDOW,
                        0,
                        0,
                        static_cast<int>(width_),
                        static_cast<int>(height_),
                        NULL,
                        NULL,
                        NULL,
                        NULL);

  if (hwnd_ == NULL) {
    Destroy();
    return false;
  }

  d3d_ = Direct3DCreate9(D3D_SDK_VERSION);
  if (d3d_ == NULL) {
    Destroy();
    return false;
  }

  D3DPRESENT_PARAMETERS d3d_params = {};

  d3d_params.Windowed = TRUE;
  d3d_params.SwapEffect = D3DSWAPEFFECT_COPY;

  IDirect3DDevice9* d3d_device;
  if (d3d_->CreateDevice(D3DADAPTER_DEFAULT,
                         D3DDEVTYPE_HAL,
                         hwnd_,
                         D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                         &d3d_params,
                         &d3d_device) != D3D_OK) {
    Destroy();
    return false;
  }
  d3d_device_ = d3d_device;
  d3d_device->Release();

  IDirect3DVertexBuffer9* vertex_buffer;
  const int kRectVertices = 4;
  if (d3d_device_->CreateVertexBuffer(kRectVertices * sizeof(D3dCustomVertex),
                                      0,
                                      D3DFVF_CUSTOMVERTEX,
                                      D3DPOOL_MANAGED,
                                      &vertex_buffer,
                                      NULL) != D3D_OK) {
    Destroy();
    return false;
  }
  vertex_buffer_ = vertex_buffer;
  vertex_buffer->Release();

  d3d_device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
  d3d_device_->SetRenderState(D3DRS_LIGHTING, FALSE);
  Resize(width_, height_);

  ShowWindow(hwnd_, SW_SHOWNOACTIVATE);
  d3d_device_->Present(NULL, NULL, NULL, NULL);

  return true;
}

D3dRenderer* D3dRenderer::Create(const char* window_title,
                                 size_t width,
                                 size_t height) {
  static ATOM wc_atom = 0;
  if (wc_atom == 0) {
    WNDCLASSA wc = {};

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
    wc.lpszClassName = kD3DClassName;

    wc_atom = RegisterClassA(&wc);
    if (wc_atom == 0)
      return nullptr;
  }

  D3dRenderer* d3d_renderer = new D3dRenderer(width, height);
  if (!d3d_renderer->Init(window_title)) {
    delete d3d_renderer;
    return nullptr;
  }

  return d3d_renderer;
}

void D3dRenderer::Resize(size_t width, size_t height) {
  width_ = width;
  height_ = height;
  IDirect3DTexture9* texture;

  d3d_device_->CreateTexture(static_cast<UINT>(width_),
                             static_cast<UINT>(height_),
                             1,
                             0,
                             D3DFMT_A8R8G8B8,
                             D3DPOOL_MANAGED,
                             &texture,
                             NULL);
  texture_ = texture;
  texture->Release();

  // Vertices for the video frame to be rendered to.
  static const D3dCustomVertex rect[] = {
    {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f},
    {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f},
    {1.0f, -1.0f, 0.0f, 1.0f, 1.0f},
    {1.0f, 1.0f, 0.0f, 1.0f, 0.0f},
  };

  void* buf_data;
  if (vertex_buffer_->Lock(0, 0, &buf_data, 0) != D3D_OK)
    return;

  memcpy(buf_data, &rect, sizeof(rect));
  vertex_buffer_->Unlock();
}

void D3dRenderer::OnFrame(const webrtc::VideoFrame& frame) {
  if (static_cast<size_t>(frame.width()) != width_ ||
      static_cast<size_t>(frame.height()) != height_) {
    Resize(static_cast<size_t>(frame.width()),
           static_cast<size_t>(frame.height()));
  }

  D3DLOCKED_RECT lock_rect;
  if (texture_->LockRect(0, &lock_rect, NULL, 0) != D3D_OK)
    return;

  ConvertFromI420(frame, VideoType::kARGB, 0,
                  static_cast<uint8_t*>(lock_rect.pBits));
  texture_->UnlockRect(0);

  d3d_device_->BeginScene();
  d3d_device_->SetFVF(D3DFVF_CUSTOMVERTEX);
  d3d_device_->SetStreamSource(0, vertex_buffer_, 0, sizeof(D3dCustomVertex));
  d3d_device_->SetTexture(0, texture_);
  d3d_device_->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
  d3d_device_->EndScene();

  d3d_device_->Present(NULL, NULL, NULL, NULL);
}
}  // namespace test
}  // namespace webrtc
