590 lines
17 KiB
C++
590 lines
17 KiB
C++
/* -LICENSE-START-
|
|
** Copyright (c) 2012 Blackmagic Design
|
|
**
|
|
** Permission is hereby granted, free of charge, to any person or organization
|
|
** obtaining a copy of the software and accompanying documentation (the
|
|
** "Software") to use, reproduce, display, distribute, sub-license, 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, in
|
|
** accordance with:
|
|
**
|
|
** (1) if the Software is obtained from Blackmagic Design, the End User License
|
|
** Agreement for the Software Development Kit ("EULA") available at
|
|
** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or
|
|
**
|
|
** (2) if the Software is obtained from any third party, such licensing terms
|
|
** as notified by that third party,
|
|
**
|
|
** and all subject to the following:
|
|
**
|
|
** (3) 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.
|
|
**
|
|
** (4) 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.
|
|
**
|
|
** A copy of the Software is available free of charge at
|
|
** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA.
|
|
**
|
|
** -LICENSE-END-
|
|
*/
|
|
//
|
|
// LoopThroughWithOpenGLCompositing.cpp
|
|
// LoopThroughWithOpenGLCompositing
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "OpenGLComposite.h"
|
|
|
|
#include <algorithm>
|
|
#include <shellapi.h>
|
|
#include <string>
|
|
|
|
#ifndef WGL_CONTEXT_MAJOR_VERSION_ARB
|
|
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
#endif
|
|
#ifndef WGL_CONTEXT_MINOR_VERSION_ARB
|
|
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
#endif
|
|
#ifndef WGL_CONTEXT_PROFILE_MASK_ARB
|
|
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
#endif
|
|
#ifndef WGL_CONTEXT_CORE_PROFILE_BIT_ARB
|
|
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
#endif
|
|
|
|
#define MAX_LOADSTRING 100
|
|
|
|
// Declaration for Window procedure
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
typedef HGLRC (WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hShareContext, const int* attribList);
|
|
|
|
namespace
|
|
{
|
|
const int kStatusPanelWidth = 680;
|
|
const int kStatusPanelHeight = 92;
|
|
const int kStatusPadding = 8;
|
|
const int kStatusLabelWidth = 58;
|
|
const int kStatusButtonWidth = 86;
|
|
const int kStatusRowHeight = 24;
|
|
const int kStatusGap = 6;
|
|
const UINT kCreateStatusStripMessage = WM_APP + 1;
|
|
|
|
enum StatusControlId
|
|
{
|
|
kControlUrlEditId = 2001,
|
|
kDocsUrlEditId = 2002,
|
|
kOscAddressEditId = 2003,
|
|
kOpenControlButtonId = 2004,
|
|
kOpenDocsButtonId = 2005
|
|
};
|
|
|
|
struct StatusStripControls
|
|
{
|
|
HWND panel = NULL;
|
|
HWND controlLabel = NULL;
|
|
HWND controlUrl = NULL;
|
|
HWND openControl = NULL;
|
|
HWND docsLabel = NULL;
|
|
HWND docsUrl = NULL;
|
|
HWND openDocs = NULL;
|
|
HWND oscLabel = NULL;
|
|
HWND oscAddress = NULL;
|
|
};
|
|
|
|
bool StatusStripCreated(const StatusStripControls& controls)
|
|
{
|
|
return controls.panel != NULL;
|
|
}
|
|
|
|
HWND CreateStatusChild(HWND parent, const char* className, const char* text, DWORD style, DWORD exStyle, int controlId)
|
|
{
|
|
return CreateWindowExA(
|
|
exStyle,
|
|
className,
|
|
text,
|
|
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | style,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
parent,
|
|
reinterpret_cast<HMENU>(static_cast<INT_PTR>(controlId)),
|
|
reinterpret_cast<HINSTANCE>(GetWindowLongPtr(parent, GWLP_HINSTANCE)),
|
|
NULL);
|
|
}
|
|
|
|
void CreateStatusStrip(HWND hWnd, StatusStripControls& controls)
|
|
{
|
|
controls.panel = CreateStatusChild(hWnd, "STATIC", "", SS_LEFT, WS_EX_CLIENTEDGE, 0);
|
|
controls.controlLabel = CreateStatusChild(hWnd, "STATIC", "Control", SS_LEFT, 0, 0);
|
|
controls.controlUrl = CreateStatusChild(hWnd, "EDIT", "", ES_AUTOHSCROLL | ES_READONLY | WS_TABSTOP, WS_EX_CLIENTEDGE, kControlUrlEditId);
|
|
controls.openControl = CreateStatusChild(hWnd, "BUTTON", "Open", BS_PUSHBUTTON | WS_TABSTOP, 0, kOpenControlButtonId);
|
|
controls.docsLabel = CreateStatusChild(hWnd, "STATIC", "Docs", SS_LEFT, 0, 0);
|
|
controls.docsUrl = CreateStatusChild(hWnd, "EDIT", "", ES_AUTOHSCROLL | ES_READONLY | WS_TABSTOP, WS_EX_CLIENTEDGE, kDocsUrlEditId);
|
|
controls.openDocs = CreateStatusChild(hWnd, "BUTTON", "Open", BS_PUSHBUTTON | WS_TABSTOP, 0, kOpenDocsButtonId);
|
|
controls.oscLabel = CreateStatusChild(hWnd, "STATIC", "OSC", SS_LEFT, 0, 0);
|
|
controls.oscAddress = CreateStatusChild(hWnd, "EDIT", "", ES_AUTOHSCROLL | ES_READONLY | WS_TABSTOP, WS_EX_CLIENTEDGE, kOscAddressEditId);
|
|
|
|
HFONT guiFont = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
|
|
HWND children[] = {
|
|
controls.controlLabel,
|
|
controls.controlUrl,
|
|
controls.openControl,
|
|
controls.docsLabel,
|
|
controls.docsUrl,
|
|
controls.openDocs,
|
|
controls.oscLabel,
|
|
controls.oscAddress
|
|
};
|
|
for (HWND child : children)
|
|
{
|
|
if (child)
|
|
SendMessage(child, WM_SETFONT, reinterpret_cast<WPARAM>(guiFont), TRUE);
|
|
}
|
|
|
|
SetWindowTextA(controls.controlUrl, "Starting control server...");
|
|
SetWindowTextA(controls.docsUrl, "Starting API docs...");
|
|
SetWindowTextA(controls.oscAddress, "Starting OSC listener...");
|
|
}
|
|
|
|
void RaiseStatusControls(const StatusStripControls& controls)
|
|
{
|
|
if (!StatusStripCreated(controls))
|
|
return;
|
|
|
|
SetWindowPos(controls.panel, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
HWND interactiveControls[] = {
|
|
controls.controlLabel,
|
|
controls.controlUrl,
|
|
controls.openControl,
|
|
controls.docsLabel,
|
|
controls.docsUrl,
|
|
controls.openDocs,
|
|
controls.oscLabel,
|
|
controls.oscAddress
|
|
};
|
|
for (HWND control : interactiveControls)
|
|
{
|
|
if (control)
|
|
SetWindowPos(control, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
|
|
void LayoutStatusStrip(HWND hWnd, const StatusStripControls& controls)
|
|
{
|
|
RECT clientRect = {};
|
|
if (!GetClientRect(hWnd, &clientRect) || !controls.panel)
|
|
return;
|
|
|
|
const int clientWidth = static_cast<int>(clientRect.right - clientRect.left);
|
|
const int clientHeight = static_cast<int>(clientRect.bottom - clientRect.top);
|
|
const int panelWidth = std::max(280, std::min(kStatusPanelWidth, clientWidth - (kStatusPadding * 2)));
|
|
const int panelHeight = kStatusPanelHeight;
|
|
const int panelLeft = kStatusPadding;
|
|
const int panelTop = std::max(kStatusPadding, clientHeight - panelHeight - kStatusPadding);
|
|
MoveWindow(controls.panel, panelLeft, panelTop, panelWidth, panelHeight, TRUE);
|
|
|
|
const int rowX = panelLeft + kStatusPadding;
|
|
const int editX = rowX + kStatusLabelWidth + kStatusGap;
|
|
const int buttonX = panelLeft + panelWidth - kStatusPadding - kStatusButtonWidth;
|
|
const int editWidth = std::max(80, buttonX - editX - kStatusGap);
|
|
const int oscWidth = std::max(80, panelLeft + panelWidth - editX - kStatusPadding);
|
|
const int row1 = panelTop + kStatusPadding;
|
|
const int row2 = row1 + kStatusRowHeight + kStatusGap;
|
|
const int row3 = row2 + kStatusRowHeight + kStatusGap;
|
|
|
|
MoveWindow(controls.controlLabel, rowX, row1 + 3, kStatusLabelWidth, kStatusRowHeight, TRUE);
|
|
MoveWindow(controls.controlUrl, editX, row1, editWidth, kStatusRowHeight, TRUE);
|
|
MoveWindow(controls.openControl, buttonX, row1, kStatusButtonWidth, kStatusRowHeight, TRUE);
|
|
MoveWindow(controls.docsLabel, rowX, row2 + 3, kStatusLabelWidth, kStatusRowHeight, TRUE);
|
|
MoveWindow(controls.docsUrl, editX, row2, editWidth, kStatusRowHeight, TRUE);
|
|
MoveWindow(controls.openDocs, buttonX, row2, kStatusButtonWidth, kStatusRowHeight, TRUE);
|
|
MoveWindow(controls.oscLabel, rowX, row3 + 3, kStatusLabelWidth, kStatusRowHeight, TRUE);
|
|
MoveWindow(controls.oscAddress, editX, row3, oscWidth, kStatusRowHeight, TRUE);
|
|
RaiseStatusControls(controls);
|
|
}
|
|
|
|
void UpdateStatusStrip(const StatusStripControls& controls, const OpenGLComposite& composite)
|
|
{
|
|
if (!StatusStripCreated(controls))
|
|
return;
|
|
|
|
SetWindowTextA(controls.controlUrl, composite.GetControlUrl().c_str());
|
|
SetWindowTextA(controls.docsUrl, composite.GetDocsUrl().c_str());
|
|
SetWindowTextA(controls.oscAddress, composite.GetOscAddress().c_str());
|
|
}
|
|
|
|
void OpenUrl(const char* url)
|
|
{
|
|
ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
|
|
void ShowUnhandledExceptionMessage(const char* prefix)
|
|
{
|
|
try
|
|
{
|
|
throw;
|
|
}
|
|
catch (const std::exception& exception)
|
|
{
|
|
std::string message = std::string(prefix) + "\n\n" + exception.what();
|
|
MessageBoxA(NULL, message.c_str(), "Unhandled exception", MB_OK | MB_ICONERROR);
|
|
}
|
|
catch (...)
|
|
{
|
|
MessageBoxA(NULL, prefix, "Unhandled exception", MB_OK | MB_ICONERROR);
|
|
}
|
|
}
|
|
|
|
// Select the pixel format for a given device context
|
|
void SetDCPixelFormat(HDC hDC)
|
|
{
|
|
int nPixelFormat;
|
|
|
|
static PIXELFORMATDESCRIPTOR pfd = {
|
|
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
|
|
1, // Version of this structure
|
|
PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap)
|
|
PFD_SUPPORT_OPENGL | // Support OpenGL calls in window
|
|
PFD_DOUBLEBUFFER, // Double buffered mode
|
|
PFD_TYPE_RGBA, // RGBA Color mode
|
|
32, // Want 32 bit color
|
|
0,0,0,0,0,0, // Not used to select mode
|
|
0,0, // Not used to select mode
|
|
0,0,0,0,0, // Not used to select mode
|
|
16, // Size of depth buffer
|
|
0, // Not used
|
|
0, // Not used
|
|
0, // Not used
|
|
0, // Not used
|
|
0,0,0 }; // Not used
|
|
|
|
// Choose a pixel format that best matches that described in pfd
|
|
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
|
|
|
|
// Set the pixel format for the device context
|
|
SetPixelFormat(hDC, nPixelFormat, &pfd);
|
|
}
|
|
|
|
HGLRC CreateModernOpenGLContext(HDC hDC)
|
|
{
|
|
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
|
|
reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
|
|
if (!wglCreateContextAttribsARB)
|
|
return NULL;
|
|
|
|
const int versionCandidates[][2] =
|
|
{
|
|
{ 4, 5 },
|
|
{ 4, 3 },
|
|
{ 3, 3 }
|
|
};
|
|
|
|
for (const auto& version : versionCandidates)
|
|
{
|
|
const int attribs[] =
|
|
{
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB, version[0],
|
|
WGL_CONTEXT_MINOR_VERSION_ARB, version[1],
|
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
0
|
|
};
|
|
|
|
HGLRC modernContext = wglCreateContextAttribsARB(hDC, 0, attribs);
|
|
if (modernContext != NULL)
|
|
return modernContext;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
MSG msg; // Windows message structure
|
|
WNDCLASS wc; // Windows class structure
|
|
HWND hWnd; // Storeage for window handle
|
|
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
|
|
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
|
|
|
|
// Initialize global strings
|
|
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
|
LoadString(hInstance, IDC_OPENGLOUTPUT, szWindowClass, MAX_LOADSTRING);
|
|
|
|
// Register Window style
|
|
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
|
wc.lpfnWndProc = (WNDPROC) WndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
// No need for background brush for OpenGL window
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = szWindowClass;
|
|
|
|
// Register the window class
|
|
if (RegisterClass(&wc) == 0)
|
|
return FALSE;
|
|
|
|
// Create the main application window
|
|
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
|
CW_USEDEFAULT, 0, 250, 250, NULL, NULL, hInstance, NULL);
|
|
|
|
// If window was not created, quit
|
|
if (hWnd == NULL)
|
|
return FALSE;
|
|
|
|
// Display the window
|
|
ShowWindow(hWnd,SW_SHOW);
|
|
UpdateWindow(hWnd);
|
|
|
|
// Process application messages until the application closes
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
return (int)msg.wParam;
|
|
}
|
|
|
|
// Window procedure, handles all messages for this program
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static HGLRC hRC = NULL; // Permenant Rendering context
|
|
static HDC hDC = NULL; // Private GDI Device context
|
|
static OpenGLComposite* pOpenGLComposite = NULL;
|
|
static bool sInteractiveResize = false;
|
|
static StatusStripControls sStatusStrip;
|
|
|
|
switch (message)
|
|
{
|
|
// Window creation, setup for OpenGL context
|
|
case WM_CREATE:
|
|
{
|
|
try
|
|
{
|
|
// Store the device context
|
|
hDC = GetDC(hWnd);
|
|
|
|
// Select the pixel format
|
|
SetDCPixelFormat(hDC);
|
|
|
|
// Create the rendering context and make it current
|
|
hRC = wglCreateContext(hDC);
|
|
wglMakeCurrent(hDC, hRC);
|
|
|
|
HGLRC modernRC = CreateModernOpenGLContext(hDC);
|
|
if (modernRC == NULL)
|
|
{
|
|
MessageBox(NULL, _T("This application requires an OpenGL 3.3+ core profile context."), _T("OpenGL initialization Error."), MB_OK);
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
|
|
wglMakeCurrent(NULL, NULL);
|
|
wglDeleteContext(hRC);
|
|
hRC = modernRC;
|
|
wglMakeCurrent(hDC, hRC);
|
|
|
|
// Initialize COM
|
|
HRESULT result;
|
|
result = CoInitialize(NULL);
|
|
if (FAILED(result))
|
|
{
|
|
MessageBox(NULL, _T("Initialization of COM failed."), _T("Application initialization Error."),MB_OK);
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
|
|
// Setup OpenGL and DeckLink capture and playout object
|
|
pOpenGLComposite = new OpenGLComposite(hWnd, hDC, hRC);
|
|
|
|
if (pOpenGLComposite->InitDeckLink())
|
|
{
|
|
wglMakeCurrent( NULL, NULL );
|
|
if (pOpenGLComposite->Start())
|
|
{
|
|
PostMessage(hWnd, kCreateStatusStripMessage, 0, 0);
|
|
break; // success
|
|
}
|
|
MessageBoxA(NULL, "The OpenGL/DeckLink runtime initialized, but playout failed to start. See the previous DeckLink start message for the failing call.", "Startup failed", MB_OK | MB_ICONERROR);
|
|
}
|
|
else
|
|
{
|
|
MessageBoxA(NULL, "The OpenGL/DeckLink runtime failed to initialize. See the previous initialization message for the failing call.", "Startup failed", MB_OK | MB_ICONERROR);
|
|
}
|
|
|
|
// Failed to initialize - cleanup
|
|
delete pOpenGLComposite;
|
|
pOpenGLComposite = NULL;
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
catch (...)
|
|
{
|
|
ShowUnhandledExceptionMessage("Startup failed while creating the OpenGL/DeckLink runtime.");
|
|
PostMessage(hWnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
case kCreateStatusStripMessage:
|
|
if (pOpenGLComposite)
|
|
{
|
|
if (!StatusStripCreated(sStatusStrip))
|
|
CreateStatusStrip(hWnd, sStatusStrip);
|
|
|
|
UpdateStatusStrip(sStatusStrip, *pOpenGLComposite);
|
|
LayoutStatusStrip(hWnd, sStatusStrip);
|
|
RECT clientRect = {};
|
|
if (GetClientRect(hWnd, &clientRect))
|
|
{
|
|
pOpenGLComposite->resizeGL(
|
|
static_cast<WORD>(clientRect.right - clientRect.left),
|
|
static_cast<WORD>(clientRect.bottom - clientRect.top));
|
|
}
|
|
InvalidateRect(hWnd, NULL, FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
try
|
|
{
|
|
if (pOpenGLComposite)
|
|
{
|
|
pOpenGLComposite->Stop();
|
|
delete pOpenGLComposite;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
ShowUnhandledExceptionMessage("Shutdown failed while tearing down the OpenGL/DeckLink runtime.");
|
|
}
|
|
|
|
// Deselect the current rendering context and delete it
|
|
wglMakeCurrent(hDC, NULL);
|
|
wglDeleteContext(hRC);
|
|
|
|
// Tell the application to terminate after the window is gone
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_ENTERSIZEMOVE:
|
|
sInteractiveResize = true;
|
|
break;
|
|
|
|
case WM_EXITSIZEMOVE:
|
|
sInteractiveResize = false;
|
|
if (pOpenGLComposite)
|
|
{
|
|
RECT clientRect = {};
|
|
if (GetClientRect(hWnd, &clientRect))
|
|
{
|
|
pOpenGLComposite->resizeGL(
|
|
static_cast<WORD>(clientRect.right - clientRect.left),
|
|
static_cast<WORD>(clientRect.bottom - clientRect.top));
|
|
}
|
|
}
|
|
InvalidateRect(hWnd, NULL, FALSE);
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
try
|
|
{
|
|
if (StatusStripCreated(sStatusStrip))
|
|
LayoutStatusStrip(hWnd, sStatusStrip);
|
|
if (pOpenGLComposite)
|
|
pOpenGLComposite->resizeGL(LOWORD(lParam), HIWORD(lParam));
|
|
}
|
|
catch (...)
|
|
{
|
|
ShowUnhandledExceptionMessage("Resize failed inside the OpenGL runtime.");
|
|
}
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
return 1;
|
|
|
|
case WM_PAINT:
|
|
try
|
|
{
|
|
PAINTSTRUCT paint = {};
|
|
BeginPaint(hWnd, &paint);
|
|
EndPaint(hWnd, &paint);
|
|
|
|
if (!sInteractiveResize && pOpenGLComposite)
|
|
{
|
|
wglMakeCurrent(hDC, hRC);
|
|
pOpenGLComposite->paintGL(true);
|
|
wglMakeCurrent( NULL, NULL );
|
|
RaiseStatusControls(sStatusStrip);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
wglMakeCurrent( NULL, NULL );
|
|
ShowUnhandledExceptionMessage("Paint failed inside the OpenGL runtime.");
|
|
}
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
try
|
|
{
|
|
if (pOpenGLComposite && (wParam == 'R' || wParam == 'r'))
|
|
{
|
|
pOpenGLComposite->ReloadShader();
|
|
InvalidateRect(hWnd, NULL, FALSE);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
ShowUnhandledExceptionMessage("Shader reload failed inside the OpenGL runtime.");
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case kOpenControlButtonId:
|
|
if (pOpenGLComposite)
|
|
{
|
|
std::string url = pOpenGLComposite->GetControlUrl();
|
|
OpenUrl(url.c_str());
|
|
}
|
|
break;
|
|
case kOpenDocsButtonId:
|
|
if (pOpenGLComposite)
|
|
{
|
|
std::string url = pOpenGLComposite->GetDocsUrl();
|
|
OpenUrl(url.c_str());
|
|
}
|
|
break;
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
}
|
|
|
|
return (0L);
|
|
}
|
|
|