/* -LICENSE-START-
** Copyright (c) 2013 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
** 
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
** 
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/


#include "stdafx.h"
#include <gl/gl.h>
#include "PreviewWindow.h"

PreviewWindow::PreviewWindow()
 : m_refCount(1), m_deckLinkScreenPreviewHelper(NULL), m_previewBox(NULL), m_previewBoxDC(NULL), m_openGLctx(NULL)
{}

PreviewWindow::~PreviewWindow()
{
	if (m_deckLinkScreenPreviewHelper != NULL)
	{
		m_deckLinkScreenPreviewHelper->Release();
		m_deckLinkScreenPreviewHelper = NULL;
	}

	if (m_openGLctx != NULL)
	{
		wglDeleteContext(m_openGLctx);
		m_openGLctx = NULL;
	}

	if (m_previewBoxDC != NULL)
	{
		m_previewBox->ReleaseDC(m_previewBoxDC);
		m_previewBoxDC = NULL;
	}
}

bool		PreviewWindow::init(CStatic *previewBox)
{
	m_previewBox = previewBox;

	// Create the DeckLink screen preview helper
	if (CoCreateInstance(CLSID_CDeckLinkGLScreenPreviewHelper, NULL, CLSCTX_ALL, IID_IDeckLinkGLScreenPreviewHelper, (void**)&m_deckLinkScreenPreviewHelper) != S_OK)
		return false;

	// Initialise OpenGL
	return initOpenGL();
}

bool		PreviewWindow::initOpenGL()
{
	PIXELFORMATDESCRIPTOR	pixelFormatDesc;
	int						pixelFormat;
	bool					result = false;

	//
	// Here, we create an OpenGL context attached to the screen preview box
	// so we can use it later on when we need to draw preview frames.

	// Get the preview box drawing context
	m_previewBoxDC = m_previewBox->GetDC();
	if (m_previewBoxDC == NULL)
		return false;

	// Ensure the preview box DC uses ARGB pixel format
	ZeroMemory(&pixelFormatDesc, sizeof(pixelFormatDesc));
	pixelFormatDesc.nSize = sizeof(pixelFormatDesc);
	pixelFormatDesc.nVersion = 1;
	pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
	pixelFormatDesc.iPixelType = PFD_TYPE_RGBA;
	pixelFormatDesc.cColorBits = 32;
	pixelFormatDesc.cDepthBits = 16;
	pixelFormatDesc.cAlphaBits = 8;
	pixelFormatDesc.iLayerType = PFD_MAIN_PLANE;
	pixelFormat = ChoosePixelFormat(m_previewBoxDC->m_hDC, &pixelFormatDesc);
	if (SetPixelFormat(m_previewBoxDC->m_hDC, pixelFormat, &pixelFormatDesc) == false)
		return false;

	// Create OpenGL rendering context
	m_openGLctx = wglCreateContext(m_previewBoxDC->m_hDC);
	if (m_openGLctx == NULL)
		return false;

	// Make the new OpenGL context the current rendering context so
	// we can initialise the DeckLink preview helper
	if (wglMakeCurrent(m_previewBoxDC->m_hDC, m_openGLctx) == FALSE)
		return false;

	if (m_deckLinkScreenPreviewHelper->InitializeGL() == S_OK)
		result = true;

	// Reset the OpenGL rendering context
	wglMakeCurrent(NULL, NULL);

	return result;
}

HRESULT 	PreviewWindow::QueryInterface(REFIID iid, LPVOID *ppv)
{
	*ppv = NULL;
	return E_NOINTERFACE;
}
ULONG		PreviewWindow::AddRef()
{
	return InterlockedIncrement((LONG*)&m_refCount);
}
ULONG		PreviewWindow::Release()
{
	ULONG		newRefValue;

	newRefValue = InterlockedDecrement((LONG*)&m_refCount);
	if (newRefValue == 0)
	{
		delete this;
		return 0;
	}

	return newRefValue;
}

HRESULT			PreviewWindow::DrawFrame(IDeckLinkVideoFrame* theFrame)
{
	// Make sure we are initialised
	if ((m_deckLinkScreenPreviewHelper == NULL) || (m_previewBoxDC == NULL) || (m_openGLctx == NULL))
		return E_FAIL;

	// First, pass the frame to the DeckLink screen preview helper
	m_deckLinkScreenPreviewHelper->SetFrame(theFrame);

	// Then set the OpenGL rendering context to the one we created before
	wglMakeCurrent(m_previewBoxDC->m_hDC, m_openGLctx);

	// and let the helper take care of the drawing
	m_deckLinkScreenPreviewHelper->PaintGL();

	// Last, reset the OpenGL rendering context
	wglMakeCurrent(NULL, NULL);

	return S_OK;
}

