Initial commit
This commit is contained in:
319
libsst-wm/Win32/SST_WMDialogBox_Win32.c
Normal file
319
libsst-wm/Win32/SST_WMDialogBox_Win32.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
SST_WMDialogBox_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Model
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
|
||||
#define BUTTON_HSPACE 16 /* Space on either side of a button */
|
||||
#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */
|
||||
#define TEXT_HSPACE 16
|
||||
#define TEXT_VSPACE 16
|
||||
|
||||
typedef struct DialogBoxData
|
||||
{
|
||||
const char* message;
|
||||
int lenMessage;
|
||||
int buttonId;
|
||||
int exitTime;
|
||||
} DialogBoxData;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static LONG dlgRegCount = 0;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static LRESULT WINAPI libsstDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static HWND createButton(HWND owner, int id, const char* label, int x, int y, int w, int h);
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
int Win32_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)parent;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
HWND hWnd;
|
||||
HWND hParentWnd = NULL;
|
||||
MSG msg;
|
||||
HDC hDC;
|
||||
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
||||
|
||||
/* Compute size of a button. This is absolutely arcane, but the 50x14 units and the /4 /8 are documented. Somewhere... */
|
||||
uint32_t units = (uint32_t)GetDialogBaseUnits();
|
||||
int horiz = (int)MulDiv((units & 0xFF), 50, 4);
|
||||
int vert = (int)MulDiv((units >> 16), 14, 8);
|
||||
int w, h;
|
||||
int returnCode;
|
||||
|
||||
/* Window rectangle computation */
|
||||
DWORD style = WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN;
|
||||
DWORD styleEx = 0;
|
||||
RECT r;
|
||||
RECT textRect;
|
||||
RECT centerOn;
|
||||
DialogBoxData* dlgData;
|
||||
|
||||
/* Allocate dialog box data */
|
||||
dlgData = (DialogBoxData*)HeapAlloc(GetProcessHeap(), 0, sizeof(DialogBoxData));
|
||||
if(dlgData == NULL)
|
||||
return -1;
|
||||
|
||||
dlgData->message = message;
|
||||
dlgData->lenMessage = (int)strlen(message);
|
||||
dlgData->buttonId = -1;
|
||||
dlgData->exitTime = 0;
|
||||
/*
|
||||
First, figure out a good area to center the dialog box on. It's highly unintuitive to have it
|
||||
it mapped in the top-left corner. We center it on the parent window (if possible) or the monitor
|
||||
otherwise.
|
||||
*/
|
||||
|
||||
/* Have a parent window? */
|
||||
if(win != NULL)
|
||||
{
|
||||
/* Then center on it */
|
||||
hParentWnd = win->hWnd;
|
||||
GetWindowRect(hParentWnd, ¢erOn);
|
||||
}
|
||||
else /* Otherwise center on default display */
|
||||
{
|
||||
FindMonitorInfo fmi;
|
||||
|
||||
/* Attempt to find the monitor associated with a display device */
|
||||
findMonitor(&displayTarget->devs[0], &fmi);
|
||||
|
||||
/* Didn't find it? */
|
||||
if(!fmi.foundIt)
|
||||
return -1;
|
||||
|
||||
/* Center on the monitor */
|
||||
centerOn.top = fmi.top;
|
||||
centerOn.left = fmi.left;
|
||||
centerOn.bottom = fmi.bottom;
|
||||
centerOn.right = fmi.right;
|
||||
}
|
||||
|
||||
/* Start the window as if it was at (0,0) */
|
||||
r.top = 0;
|
||||
r.left = 0;
|
||||
r.bottom = 2*BUTTON_VSPACE+vert; /* Enough space for a button and vertical padding above and below it */
|
||||
r.right = (LONG)nrButtons*(horiz + BUTTON_HSPACE)+BUTTON_HSPACE;
|
||||
|
||||
/* Now we need to compute the area requried to display the text. This will be summed with the area required for the buttons on the Y axis, but
|
||||
the X axis will be the maximum of the two. */
|
||||
/* 1) Create a fake DC to compute the size of the text's rect */
|
||||
hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
|
||||
SelectObject(hDC, (HGDIOBJ)hFont);
|
||||
|
||||
/* 2) Actually compute the rect using DrawTextEx() and DT_CALCRECT. */
|
||||
memset(&textRect, 0, sizeof(textRect));
|
||||
DrawTextExA(hDC, (LPSTR)dlgData->message, dlgData->lenMessage, &textRect, DT_CALCRECT | DT_TOP | DT_LEFT, NULL);
|
||||
DeleteDC(hDC);
|
||||
|
||||
/* 3) Add a border around the entire thing */
|
||||
textRect.bottom += 2*TEXT_VSPACE;
|
||||
textRect.right += 2*TEXT_HSPACE;
|
||||
|
||||
/* For the X-axis, we want the maximum of the amount of space it takes to display buttons and text */
|
||||
if(r.right < textRect.right)
|
||||
r.right = textRect.right;
|
||||
|
||||
/* For the Y-aaxis, just append space to the top of dialog box for the text rect */
|
||||
r.bottom += textRect.bottom;
|
||||
|
||||
/* Move the window to the center of the screen: */
|
||||
/* 1) Compute width and height of window */
|
||||
w = r.right - r.left;
|
||||
h = r.bottom - r.top;
|
||||
|
||||
AdjustWindowRectEx(&r, style, FALSE, styleEx);
|
||||
|
||||
/* After we adjusted the size of the window so that the client area is constant, we need
|
||||
to move it back to (0,0). */
|
||||
if(r.top != 0)
|
||||
{
|
||||
LONG d = -r.top;
|
||||
|
||||
r.top = 0;
|
||||
r.bottom += d;
|
||||
}
|
||||
if(r.left != 0)
|
||||
{
|
||||
LONG d = -r.left;
|
||||
|
||||
r.left = 0;
|
||||
r.right += d;
|
||||
}
|
||||
|
||||
/* 2) Adjust so it fits on the screen by doing: `adjust = (center - size) /2` */
|
||||
r.left += ((centerOn.right - centerOn.left) - w) / 2;
|
||||
r.right += ((centerOn.right - centerOn.left) - w) / 2;
|
||||
r.top += ((centerOn.bottom - centerOn.top) - h) / 2;
|
||||
r.bottom += ((centerOn.bottom - centerOn.top) - h) / 2;
|
||||
|
||||
/* You can't create a window without registering the class, so let's do it now. Since
|
||||
this function has "Concurrent" access, use an atomic operation to decide if it is necessary. */
|
||||
if(InterlockedIncrement(&dlgRegCount) == 1)
|
||||
{
|
||||
WNDCLASSEXA wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpszClassName = SST_DLGCLASS;
|
||||
wc.hInstance = GetModuleHandleA(NULL);
|
||||
wc.lpfnWndProc = libsstDlgProc;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.hbrBackground = (HBRUSH)(uintptr_t)(COLOR_WINDOW+1);
|
||||
RegisterClassExA(&wc);
|
||||
} /* TODO: I suppose it is possible that someone could turn this into a race condition. Priority = lowest */
|
||||
|
||||
/* FINALLY, create the dialog window */
|
||||
hWnd = CreateWindowExA(styleEx,
|
||||
SST_DLGCLASS,
|
||||
caption,
|
||||
style,
|
||||
r.left, r.top, /* XY position */
|
||||
r.right-r.left, r.bottom-r.top, /* Size */
|
||||
hParentWnd,
|
||||
(NULL),
|
||||
GetModuleHandleA(NULL),
|
||||
NULL);
|
||||
|
||||
/* Made the window successfully? */
|
||||
if(hWnd != NULL)
|
||||
{
|
||||
int i;
|
||||
POINT bottomRight;
|
||||
RECT clientRect;
|
||||
SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)dlgData);
|
||||
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
|
||||
/* Get the coordinates of the bottom right pixel */
|
||||
GetClientRect(hWnd, &clientRect);
|
||||
bottomRight.x = clientRect.right;
|
||||
bottomRight.y = clientRect.bottom;
|
||||
|
||||
/* Create the dialog buttons in reverse order starting at the right end of the dialog and moving left */
|
||||
for(i=0; i<nrButtons; i++)
|
||||
{
|
||||
HWND hButton = createButton(hWnd, nrButtons-1-i, buttons[nrButtons-1-i], bottomRight.x-((i+1)*(BUTTON_HSPACE+horiz)), bottomRight.y-(BUTTON_VSPACE+vert), horiz, vert);
|
||||
|
||||
/* Set the font on them too */
|
||||
SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
while(PeekMessageA(&msg, hWnd, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
} while(!dlgData->exitTime);
|
||||
}
|
||||
|
||||
returnCode = dlgData->buttonId;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0,dlgData);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static LRESULT WINAPI libsstDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DialogBoxData* dlgData = (DialogBoxData*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
|
||||
|
||||
|
||||
switch(msg)
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
RECT r;
|
||||
HDC hDC;
|
||||
|
||||
|
||||
if(dlgData)
|
||||
{
|
||||
hDC = BeginPaint(hWnd, &ps);
|
||||
|
||||
SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
|
||||
|
||||
GetClientRect(hWnd, &r);
|
||||
|
||||
r.left += TEXT_HSPACE;
|
||||
r.right -= TEXT_HSPACE;
|
||||
r.top += TEXT_VSPACE;
|
||||
r.bottom -= TEXT_VSPACE;
|
||||
|
||||
DrawTextExA(hDC, (LPSTR)dlgData->message, dlgData->lenMessage, &r, DT_TOP | DT_LEFT, NULL);
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Aborting the dialog */
|
||||
case WM_CLOSE:
|
||||
dlgData->buttonId = -1;
|
||||
dlgData->exitTime = 1;
|
||||
DestroyWindow(hWnd);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
if(HIWORD(wParam) == BN_CLICKED)
|
||||
{
|
||||
dlgData->buttonId = (int)LOWORD(wParam);
|
||||
dlgData->exitTime = 1;
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static HWND createButton(HWND owner, int id, const char* label, int x, int y, int w, int h)
|
||||
{
|
||||
HWND hWnd = CreateWindowExA(0,
|
||||
"BUTTON",
|
||||
label,
|
||||
WS_TABSTOP|WS_VISIBLE|
|
||||
WS_CHILD|BS_DEFPUSHBUTTON,
|
||||
x, y,
|
||||
w, h,
|
||||
owner,
|
||||
(HMENU)(uintptr_t)id,
|
||||
GetModuleHandleA(NULL),
|
||||
NULL);
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
268
libsst-wm/Win32/SST_WMEnum_Win32.c
Normal file
268
libsst-wm/Win32/SST_WMEnum_Win32.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
SST_WMEnum_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/7/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Enumerates graphics adapters and screens.
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WM.h>
|
||||
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
|
||||
#include <string.h> /* strlen() etc. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_GraphicsEnumerator Win32_CreateGraphicsEnumerator(void)
|
||||
{
|
||||
DISPLAY_DEVICEA* devsFound = NULL;
|
||||
char* adapterNames;
|
||||
char* adapterGUIDs;
|
||||
size_t* screenCount;
|
||||
size_t adapterCount;
|
||||
size_t devCount = 0;
|
||||
size_t ASPairCount = 0;
|
||||
size_t i;
|
||||
SST_GraphicsEnumerator_Win32* enumerator;
|
||||
ASMapEntry* ASMap;
|
||||
HANDLE hProcessHeap;
|
||||
|
||||
/* Get a list of Win32 display devices */
|
||||
devsFound = get_win32devs(&devCount);
|
||||
if(devsFound == NULL)
|
||||
return NULL;
|
||||
|
||||
hProcessHeap = GetProcessHeap();
|
||||
|
||||
/* Get a list of the graphics adapters' names */
|
||||
adapterNames = get_adapters(devsFound, devCount, &adapterCount, &adapterGUIDs);
|
||||
if(adapterNames == NULL)
|
||||
{
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make a map of adapter->screen count */
|
||||
screenCount = HeapAlloc(hProcessHeap, 0, adapterCount*sizeof(size_t));
|
||||
if(screenCount == NULL)
|
||||
{
|
||||
HeapFree(hProcessHeap, 0, adapterGUIDs);
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i<adapterCount; i++)
|
||||
screenCount[i] = 0;
|
||||
|
||||
/* Attempt to build the adapter-screen map */
|
||||
ASMap = build_asmap(devsFound, adapterGUIDs, devCount, adapterCount, screenCount, &ASPairCount);
|
||||
if(ASMap == NULL)
|
||||
{
|
||||
HeapFree(hProcessHeap, 0, adapterGUIDs);
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
HeapFree(hProcessHeap, 0, screenCount);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Done with GUIDs */
|
||||
HeapFree(hProcessHeap, 0, adapterGUIDs);
|
||||
|
||||
/* Get the list of video modes for each adapter-screen pair */
|
||||
for(i=0; i<ASPairCount; i++)
|
||||
{
|
||||
size_t vmodeCount;
|
||||
SST_VideoMode* vmodes;
|
||||
|
||||
vmodes = get_vmodes(ASMap[i].dev, &vmodeCount, &ASMap[i].defaultVmode);
|
||||
if(vmodes == NULL)
|
||||
{
|
||||
size_t j;
|
||||
for(j=0; j<i; j++)
|
||||
HeapFree(hProcessHeap, 0, ASMap[i].vmodes);
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
HeapFree(hProcessHeap, 0, screenCount);
|
||||
HeapFree(hProcessHeap, 0, ASMap);
|
||||
return NULL;
|
||||
}
|
||||
/* Save the screens for this */
|
||||
ASMap[i].vmodeCount = vmodeCount;
|
||||
ASMap[i].vmodes = vmodes;
|
||||
}
|
||||
|
||||
/* Prepare a structure to return... */
|
||||
enumerator = HeapAlloc(hProcessHeap, 0, sizeof(SST_GraphicsEnumerator_Win32));
|
||||
if(enumerator == NULL)
|
||||
{
|
||||
/* Doh! So close :\ */
|
||||
size_t j;
|
||||
for(j=0; j<i; j++)
|
||||
HeapFree(hProcessHeap, 0, ASMap[i].vmodes);
|
||||
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
HeapFree(hProcessHeap, 0, screenCount);
|
||||
HeapFree(hProcessHeap, 0, ASMap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save fields */
|
||||
enumerator->adapterNames = adapterNames;
|
||||
enumerator->adapterCount = adapterCount;
|
||||
enumerator->devCount = devCount;
|
||||
enumerator->devsFound = devsFound;
|
||||
enumerator->screenCount = screenCount;
|
||||
enumerator->ASMap = ASMap;
|
||||
enumerator->ASPairCount = ASPairCount;
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static size_t Win32_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
|
||||
return enumWin32->adapterCount;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t len;
|
||||
const char* name = &enumWin32->adapterNames[adapterId * ADAPTER_NAME_STRLEN];
|
||||
|
||||
len = strlen(name);
|
||||
|
||||
/* Query name length */
|
||||
if(nameReturn == NULL)
|
||||
{
|
||||
*bufferSize = len+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t copyAmount;
|
||||
|
||||
/* Nothing to do? */
|
||||
if(*bufferSize == 0)
|
||||
return;
|
||||
|
||||
/* Use min(len, (*bufferSize)-1) */
|
||||
copyAmount = len;
|
||||
if(copyAmount > (*bufferSize)-1)
|
||||
copyAmount = (*bufferSize)-1;
|
||||
|
||||
memcpy(nameReturn, name, copyAmount);
|
||||
nameReturn[copyAmount] = '\0';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static size_t Win32_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
|
||||
return enumWin32->screenCount[adapterId];
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t i;
|
||||
ASMapEntry* entry = NULL;
|
||||
|
||||
/* Determine which adapter-screen pair to use */
|
||||
for(i=0; i<enumWin32->ASPairCount; i++)
|
||||
{
|
||||
entry = &enumWin32->ASMap[i];
|
||||
if(entry->adapter == adapterId && entry->screen == screenId)
|
||||
{
|
||||
entry = &enumWin32->ASMap[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* When 'modesReturn' is null, user is getting mode count */
|
||||
if(modesReturn == NULL)
|
||||
*modeCountReturn = entry->vmodeCount;
|
||||
else /* else, copy '*modeCountReturn' number of modes */
|
||||
{
|
||||
size_t nrCopy = *modeCountReturn;
|
||||
if(nrCopy > entry->vmodeCount)
|
||||
nrCopy = entry->vmodeCount;
|
||||
|
||||
memcpy(modesReturn, entry->vmodes, sizeof(SST_VideoMode) * nrCopy);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t i;
|
||||
|
||||
for(i=0; i<enumWin32->ASPairCount; i++)
|
||||
{
|
||||
if(enumWin32->ASMap[i].adapter == adapterId && enumWin32->ASMap[i].screen == screenId)
|
||||
{
|
||||
*mode = enumWin32->ASMap[i].defaultVmode;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t i;
|
||||
HANDLE hProcessHeap;
|
||||
|
||||
hProcessHeap = GetProcessHeap();
|
||||
|
||||
HeapFree(hProcessHeap, 0, enumWin32->adapterNames);
|
||||
HeapFree(hProcessHeap, 0, enumWin32->devsFound);
|
||||
HeapFree(hProcessHeap, 0, enumWin32->screenCount);
|
||||
|
||||
/* Free modes for each adapter-screen pair */
|
||||
for(i=0; i<enumWin32->ASPairCount; i++)
|
||||
HeapFree(hProcessHeap, 0, enumWin32->ASMap[i].vmodes);
|
||||
HeapFree(hProcessHeap, 0, enumWin32->ASMap);
|
||||
|
||||
HeapFree(hProcessHeap, 0, enumWin32);
|
||||
}
|
||||
|
||||
struct SST_WM_EnumFuncs Win32_EnumFuncs = {
|
||||
Win32_CreateGraphicsEnumerator,
|
||||
Win32_GetEnumAdapterCount,
|
||||
Win32_GetEnumAdapterName,
|
||||
Win32_GetEnumScreenCount,
|
||||
Win32_GetEnumVideoModes,
|
||||
Win32_GetEnumCurrentVideoMode,
|
||||
Win32_DestroyGraphicsEnumerator
|
||||
};
|
||||
90
libsst-wm/Win32/SST_WMEvent_Win32.c
Normal file
90
libsst-wm/Win32/SST_WMEvent_Win32.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
SST_WMEvent_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/5/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Window event functions
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMEvent.h>
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
static void copyAndRemoveUserEvent(SST_DisplayTarget_Win32* displayTarget, SST_WMEvent* eventReturn);
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn)
|
||||
{
|
||||
MSG msg;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
SST_Window_Win32* win;
|
||||
int found = 0;
|
||||
|
||||
/* First, get Win32 messages and dispatch to winproc. We
|
||||
do this immediately, otherwise the OS thinks we've hung. */
|
||||
while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
|
||||
/* Check for user events */
|
||||
if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
/* Now check each window's event queue */
|
||||
win = displayTarget->firstWindow;
|
||||
while(win)
|
||||
{
|
||||
if(RemoveFromEQ(&win->eventQueue, eventReturn))
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
win = win->next;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Platform-specific code dealing with user event queue */
|
||||
|
||||
static void Win32_lockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
EnterCriticalSection(&displayTarget->userEventLock);
|
||||
}
|
||||
|
||||
static void Win32_unlockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
LeaveCriticalSection(&displayTarget->userEventLock);
|
||||
}
|
||||
|
||||
static EventQueue* Win32_getUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
return &displayTarget->userEventQueue;
|
||||
}
|
||||
|
||||
const struct SST_WM_EventFuncs Win32_EventFuncs = {
|
||||
Win32_GetEvent,
|
||||
Win32_getUserEventQueue,
|
||||
Win32_lockUserEventQueue,
|
||||
Win32_unlockUserEventQueue
|
||||
};
|
||||
26
libsst-wm/Win32/SST_WMNonPortable_Win32.c
Normal file
26
libsst-wm/Win32/SST_WMNonPortable_Win32.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
SST_WMNonPortable_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/1/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Non-portable API calls in libsst-wm for the Win32 platform
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
|
||||
HWND SST_WM_GetHWNDWin32(SST_Window window)
|
||||
{
|
||||
return ((SST_Window_Win32*)window)->hWnd;
|
||||
}
|
||||
|
||||
848
libsst-wm/Win32/SST_WMOpenGL_Win32.c
Normal file
848
libsst-wm/Win32/SST_WMOpenGL_Win32.c
Normal file
@@ -0,0 +1,848 @@
|
||||
/*
|
||||
SST_WMOpenGL_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/28/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL context creation
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
#include <GL/gl.h>
|
||||
|
||||
/*
|
||||
NOTE: Herein lines madness. Abandon faith all ye who would enter.
|
||||
|
||||
Windows has been notoriously bad at keeping up with OpenGL progress. In particular, to get a modern context,
|
||||
one must:
|
||||
|
||||
1) Create a fake window
|
||||
2) Select a fake pixel format
|
||||
4) Create a fake GL context
|
||||
5) Bind that context
|
||||
6) Resolve the wglGetExtensionStringARB() symbol
|
||||
7) Call wglGetExtensionStringARB() and check for various WGL extensions
|
||||
8) Resolve required extensions
|
||||
9) Select a real pixel format
|
||||
10) Create a real context
|
||||
|
||||
This doesn't even consider the complexity of handling issues such as pushing/popping the current OpenGL context
|
||||
so that calling SST_WM_CreateOpenGLContext() doesn't result in losing the currently active context, or providing
|
||||
fallbacks in case the person wants GL <= 2.x and doesn't have the GL >= 3.x WGL extensions. So much madness.
|
||||
*/
|
||||
|
||||
/* Create a temporary 1x1 window that is invisible */
|
||||
static HWND createTmpWindow(SST_DisplayTarget_Win32* copyFrom);
|
||||
|
||||
/* Create OpenGL context that would probably work with Windows 95 */
|
||||
static SST_OpenGLContext legacyCreateOpenGLContext(SST_DisplayTarget_Win32* win, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn, HMODULE opengl32, WGLFunctions* wgl);
|
||||
|
||||
/* Use wglChoosePixelFormatARB() to find a useful pixel format */
|
||||
static int modernChoosePixelFormat(HDC hDC, WGLFunctions* wgl, const SST_OpenGLContextAttributes* attribs);
|
||||
|
||||
/* Get selected pixel format return value information */
|
||||
static void modernGetPixelInfo(HDC hDC, int format, WGLFunctions* wgl, SST_OpenGLContextAttributes* selectedAttribsReturn);
|
||||
|
||||
static int* addAttr(int* ptr, int x, int y)
|
||||
{
|
||||
ptr[0] = x;
|
||||
ptr[1] = y;
|
||||
return ptr + 2;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Win32_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
HMODULE opengl32;
|
||||
HWND hTmpWnd, hTmpWnd2;
|
||||
HDC hTmpDC, hTmpDC2, oldDC = NULL;
|
||||
HGLRC hTmpCtx, oldRC = NULL;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
WGLFunctions wgl;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
SST_OpenGLContext_Win32* glctx;
|
||||
int format;
|
||||
int OK;
|
||||
|
||||
/* Win32 doesn't have OpenGL ES AFAIK. */
|
||||
if(apiType == SSTGL_OPENGL_ES)
|
||||
return NULL;
|
||||
|
||||
/* Load opengl32.dll */
|
||||
opengl32 = LoadLibraryA("opengl32.dll");
|
||||
if(opengl32 == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(&wgl, 0, sizeof(wgl));
|
||||
resolveWGLSymbols(opengl32, &wgl);
|
||||
|
||||
/*
|
||||
OK, this next code attempts to create an invisible window which can then be used
|
||||
to bind a fake GL context to. This allows us to grab WGL extensions for advanced
|
||||
OpenGL context creation (i.e. forward compatible contexts). If this isn't supported,
|
||||
then old style context creation will be used as a fallback.
|
||||
*/
|
||||
hTmpWnd = createTmpWindow(displayTarget);
|
||||
if(hTmpWnd == NULL)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Grab the window's DC */
|
||||
hTmpDC = GetDC(hTmpWnd);
|
||||
|
||||
/* Initialize pixel format descriptor to find 24-bit color / double-buffered / render to window */
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 24;
|
||||
pfd.cRedBits = 8;
|
||||
pfd.cGreenBits = 8;
|
||||
pfd.cBlueBits = 8;
|
||||
pfd.cDepthBits = 24;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
/* Attempt to find a matching pixel format */
|
||||
OK = 0;
|
||||
hTmpCtx = NULL;
|
||||
format = ChoosePixelFormat(hTmpDC, &pfd);
|
||||
if(format > 0)
|
||||
{
|
||||
/* Attempt to set the pixel format */
|
||||
OK = (int)SetPixelFormat(hTmpDC, format, &pfd);
|
||||
if(OK)
|
||||
{
|
||||
/* Create the context */
|
||||
hTmpCtx = wgl.CreateContext(hTmpDC);
|
||||
OK = (hTmpCtx != NULL);
|
||||
|
||||
/* Bind it */
|
||||
if(OK)
|
||||
{
|
||||
/* Save old context */
|
||||
oldDC = wgl.GetCurrentDC();
|
||||
oldRC = wgl.GetCurrentContext();
|
||||
|
||||
OK = (int)wgl.MakeCurrent(hTmpDC, hTmpCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed in any of these steps? */
|
||||
if(!OK)
|
||||
{
|
||||
if(hTmpCtx != NULL)
|
||||
{
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
|
||||
/* Restore old context (since wglMakeCurrent() failed with new context) */
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
|
||||
}
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Resolve context-specific strings */
|
||||
resolveWGLExtSymbols(hTmpDC, &wgl);
|
||||
|
||||
/* Only "legacy" context functions allowed? */
|
||||
if(wgl.ChoosePixelFormatARB == NULL || wgl.CreateContextAttribsARB == NULL)
|
||||
{
|
||||
/* Remove temporary context / window, they aren't needed for legacy contexts */
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
|
||||
/* Just make a legacy context */
|
||||
return legacyCreateOpenGLContext(displayTarget, attribs, selectedAttribsReturn, opengl32, &wgl);
|
||||
}
|
||||
else /* "Modern" context creation */
|
||||
{
|
||||
#define MAX_CTX_ATTRS 16
|
||||
int contextAttrs[MAX_CTX_ATTRS];
|
||||
int* ptr;
|
||||
HGLRC hGLRC;
|
||||
size_t i;
|
||||
int ctxFlags = 0;
|
||||
|
||||
/* Create another set of temporary handles. Since we already called
|
||||
SetPixelFormat() on hTmpDC, we can't set it to the new pixel format
|
||||
that we picked with modernChoosePixelFormat(). Thus, if we do wglCreateContext() with
|
||||
hTmpDC, we'll get an invalid context. Instead, create a new window/DC and use the new
|
||||
pixel format. */
|
||||
hTmpWnd2 = createTmpWindow(displayTarget);
|
||||
hTmpDC2 = GetDC(hTmpWnd2);
|
||||
|
||||
/* Choose a pixel format */
|
||||
format = modernChoosePixelFormat(hTmpDC2, &wgl, attribs);
|
||||
if(format == 0)
|
||||
{
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
}
|
||||
SetPixelFormat(hTmpDC2, format, NULL);
|
||||
|
||||
i = 0;
|
||||
|
||||
if(attribs->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
ptr = contextAttrs;
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, attribs->contextVersionMajor);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, attribs->contextVersionMinor);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0);
|
||||
|
||||
/* If WGL_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(wgl.supportsProfiles)
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (attribs->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Legacy-free? */
|
||||
if(!attribs->legacyEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(attribs->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = 0;
|
||||
|
||||
|
||||
|
||||
/* Create the OpenGL context */
|
||||
hGLRC = wgl.CreateContextAttribsARB(hTmpDC2, NULL, contextAttrs);
|
||||
glctx = (SST_OpenGLContext_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(hGLRC == NULL || glctx == NULL)
|
||||
{
|
||||
if(hGLRC != NULL)
|
||||
wgl.DeleteContext(hGLRC);
|
||||
if(glctx != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, glctx);
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
ReleaseDC(hTmpWnd2, hTmpDC2);
|
||||
DestroyWindow(hTmpWnd2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
glctx->displayTarget = displayTarget;
|
||||
glctx->context = hGLRC;
|
||||
glctx->hDCActive = NULL;
|
||||
glctx->hSlaveWnd = NULL;
|
||||
glctx->opengl32 = opengl32;
|
||||
glctx->pixelFormat = format;
|
||||
glctx->wgl = wgl;
|
||||
glctx->isLegacy = FALSE;
|
||||
glctx->ctxVersion[0] = (short)attribs->contextVersionMajor;
|
||||
glctx->ctxVersion[1] = (short)attribs->contextVersionMinor;
|
||||
glctx->legacyEnabled = attribs->legacyEnabled? TRUE : FALSE;
|
||||
glctx->debugEnabled = attribs->debugEnabled? TRUE : FALSE;
|
||||
|
||||
if(selectedAttribsReturn)
|
||||
{
|
||||
modernGetPixelInfo(hTmpDC2, format, &wgl, selectedAttribsReturn);
|
||||
selectedAttribsReturn->contextVersionMajor = attribs->contextVersionMajor;
|
||||
selectedAttribsReturn->contextVersionMinor = attribs->contextVersionMinor;
|
||||
selectedAttribsReturn->legacyEnabled = (attribs->legacyEnabled ? 1 : 0);
|
||||
selectedAttribsReturn->debugEnabled = (ctxFlags & WGL_CONTEXT_DEBUG_BIT_ARB ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Delete temporary window */
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
ReleaseDC(hTmpWnd2, hTmpDC2);
|
||||
DestroyWindow(hTmpWnd2);
|
||||
}
|
||||
|
||||
return glctx;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Win32_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext)
|
||||
{
|
||||
SST_OpenGLContext_Win32* master = (SST_OpenGLContext_Win32*)masterGLContext;
|
||||
SST_OpenGLContext_Win32* slave;
|
||||
HWND hInvisWnd;
|
||||
FindMonitorInfo fmi;
|
||||
HDC hDC = NULL;
|
||||
HGLRC hGLRC = NULL;
|
||||
BOOL ok;
|
||||
const WGLFunctions* wgl = &master->wgl;
|
||||
|
||||
/* Since the slave context merely needs to be on *a* screen controlled by the display target, just use the first one */
|
||||
findMonitor(&master->displayTarget->devs[0], &fmi);
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */
|
||||
hInvisWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL);
|
||||
if(hInvisWnd == NULL)
|
||||
return NULL;
|
||||
ShowWindow(hInvisWnd, SW_HIDE);
|
||||
|
||||
/* Allocate context structure */
|
||||
slave = HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(slave == NULL)
|
||||
{
|
||||
DestroyWindow(hInvisWnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ok = FALSE;
|
||||
hDC = GetDC(hInvisWnd);
|
||||
|
||||
/* If master context was done using legacy functions... */
|
||||
if(master->isLegacy)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
/* Get the PFD for this pixel foramt */
|
||||
DescribePixelFormat(hDC, master->pixelFormat, sizeof(pfd), &pfd);
|
||||
|
||||
/* Set it */
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, &pfd))
|
||||
{
|
||||
hGLRC = wgl->CreateContext(hDC);
|
||||
if(hGLRC != NULL)
|
||||
{
|
||||
if(wgl->ShareLists(master->context, hGLRC))
|
||||
ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else /* Modern OpenGL functions */
|
||||
{
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, NULL))
|
||||
{
|
||||
HGLRC oldRC;
|
||||
HDC oldDC;
|
||||
|
||||
oldDC = wgl->GetCurrentDC();
|
||||
oldRC = wgl->GetCurrentContext();
|
||||
|
||||
/* Bind master context so we can call wgl extension functions. Note that we're using
|
||||
the invisible window's HDC. This should work because we just set the pixel format to be
|
||||
identical to the master context, meaning they should be compatible */
|
||||
if(wgl->MakeCurrent(hDC, master->context))
|
||||
{
|
||||
int attrs[16];
|
||||
int* ptr = attrs;
|
||||
int ctxFlags;
|
||||
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, master->ctxVersion[0]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, master->ctxVersion[1]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0);
|
||||
|
||||
/* If WGL_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(wgl->supportsProfiles)
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (master->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Legacy-free? */
|
||||
if(!master->legacyEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = 0;
|
||||
|
||||
/* Create the new context, sharing with the master context */
|
||||
hGLRC = wgl->CreateContextAttribsARB(hDC, master->context, attrs);
|
||||
if(hGLRC != NULL)
|
||||
ok = TRUE;
|
||||
}
|
||||
|
||||
/* Restore old context */
|
||||
wgl->MakeCurrent(oldDC, oldRC);
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with the DC */
|
||||
if(hDC)
|
||||
ReleaseDC(hInvisWnd, hDC);
|
||||
|
||||
/* Did we succeed in making the slave context? */
|
||||
if(ok)
|
||||
{
|
||||
/* Set up slave context info */
|
||||
slave->context = hGLRC;
|
||||
slave->displayTarget = master->displayTarget;
|
||||
slave->hDCActive = NULL;
|
||||
slave->hSlaveWnd = hInvisWnd;
|
||||
slave->isLegacy = master->isLegacy;
|
||||
slave->opengl32 = LoadLibraryA("opengl32.dll"); /* Need to increase ref count for opengl32.dll */
|
||||
slave->pixelFormat = master->pixelFormat;
|
||||
slave->wgl = master->wgl; /* TODO: should be safe, right? context dependent, but same device/GL impl... */
|
||||
slave->ctxVersion[0] = master->ctxVersion[0];
|
||||
slave->ctxVersion[1] = master->ctxVersion[1];
|
||||
slave->legacyEnabled = master->legacyEnabled;
|
||||
slave->debugEnabled = master->debugEnabled;
|
||||
}
|
||||
else /* Failure, clean up */
|
||||
{
|
||||
if(hGLRC)
|
||||
master->wgl.DeleteContext(hGLRC);
|
||||
|
||||
DestroyWindow(hInvisWnd);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, slave);
|
||||
slave = NULL;
|
||||
}
|
||||
|
||||
return slave;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SwapOpenGLBuffers(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx;
|
||||
|
||||
SwapBuffers(glctx->hDCActive);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window)
|
||||
{
|
||||
SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx;
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
/* Unbinding a context from a thread */
|
||||
if(ctx == NULL)
|
||||
{
|
||||
HMODULE opengl32;
|
||||
|
||||
/* We actually need some WGL symbols. Oops. That's OK, we can just grab the symbol */
|
||||
pf_wglMakeCurrent sst_wglMakeCurrent;
|
||||
pf_wglGetCurrentDC sst_wglGetCurrentDC;
|
||||
|
||||
/* We use LoadLibrary() instead of GetModuleHandle() so that we don't unmap the DLL
|
||||
in the middle of using it. */
|
||||
opengl32 = LoadLibraryA("opengl32.dll");
|
||||
if(opengl32)
|
||||
{
|
||||
HDC hDC;
|
||||
HWND hWnd;
|
||||
|
||||
sst_wglMakeCurrent = (pf_wglMakeCurrent)GetProcAddress(opengl32, "wglMakeCurrent");
|
||||
sst_wglGetCurrentDC = (pf_wglGetCurrentDC)GetProcAddress(opengl32, "wglGetCurrentDC");
|
||||
|
||||
/* Release the DC */
|
||||
hDC = sst_wglGetCurrentDC();
|
||||
hWnd = WindowFromDC(hDC);
|
||||
if(hDC != NULL && hWnd != NULL)
|
||||
ReleaseDC(hWnd, hDC);
|
||||
|
||||
/* OK, unbind it */
|
||||
sst_wglMakeCurrent(NULL, NULL);
|
||||
|
||||
FreeLibrary(opengl32);
|
||||
}
|
||||
|
||||
/* OK */
|
||||
return 1;
|
||||
}
|
||||
else /* Have a valid context */
|
||||
{
|
||||
HDC hDC, oldDC;
|
||||
HGLRC oldRC;
|
||||
|
||||
if( (glctx->hSlaveWnd != NULL && win != NULL) || /* Slave context provided a SST_Window */
|
||||
(glctx->hSlaveWnd == NULL && win == NULL) /* Master context with no SST_Window */
|
||||
)
|
||||
{
|
||||
/* Both are illegal according the the functions */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get old context info */
|
||||
oldDC = glctx->wgl.GetCurrentDC();
|
||||
oldRC = glctx->wgl.GetCurrentContext();
|
||||
|
||||
/* First, are we re-binding the same context? If so, then just return "success" */
|
||||
if( oldDC != NULL && oldRC != NULL &&
|
||||
oldDC == glctx->hDCActive && oldRC == glctx->context)
|
||||
return 1;
|
||||
|
||||
/* Binding master context to a window */
|
||||
if(win != NULL)
|
||||
{
|
||||
hDC = GetDC(win->hWnd);
|
||||
|
||||
/* Haven't set the pixel format for this window yet? */
|
||||
if(!win->setPixelFormat)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
DescribePixelFormat(hDC, glctx->pixelFormat, sizeof(pfd), &pfd);
|
||||
|
||||
if(SetPixelFormat(hDC, glctx->pixelFormat, &pfd))
|
||||
{
|
||||
/* OK, mark that we've set this window's pixel format once, and we won't do it again. */
|
||||
win->setPixelFormat = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Failed to set this window's pixel format, so we can't do much */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Bind slave context */
|
||||
{
|
||||
hDC = GetDC(glctx->hSlaveWnd);
|
||||
|
||||
}
|
||||
|
||||
/* Make current */
|
||||
if(!glctx->wgl.MakeCurrent(hDC, glctx->context))
|
||||
{
|
||||
/* Failed -- restore old context settings */
|
||||
glctx->wgl.MakeCurrent(oldDC, oldRC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Since we were successful, release the old DC */
|
||||
if(oldDC)
|
||||
{
|
||||
HWND hWnd = WindowFromDC(oldDC);
|
||||
if(hWnd)
|
||||
ReleaseDC(hWnd, oldDC);
|
||||
}
|
||||
|
||||
/* Save window / DC */
|
||||
glctx->hDCActive = hDC;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyOpenGLContext(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx;
|
||||
|
||||
if(glctx->hSlaveWnd)
|
||||
DestroyWindow(glctx->hSlaveWnd);
|
||||
|
||||
glctx->wgl.DeleteContext(glctx->context);
|
||||
FreeLibrary(glctx->opengl32);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, glctx);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static HWND createTmpWindow(SST_DisplayTarget_Win32* copyFrom)
|
||||
{
|
||||
HWND hTmpWnd;
|
||||
FindMonitorInfo fmi;
|
||||
|
||||
/* Find the first monitor */
|
||||
findMonitor(©From->devs[0], &fmi);
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */
|
||||
hTmpWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL);
|
||||
if(hTmpWnd == NULL)
|
||||
return NULL;
|
||||
|
||||
ShowWindow(hTmpWnd, SW_HIDE);
|
||||
|
||||
return hTmpWnd;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_OpenGLContext legacyCreateOpenGLContext(SST_DisplayTarget_Win32* displayTarget, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn, HMODULE opengl32, WGLFunctions* wgl)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
HWND hWnd;
|
||||
HDC hDC, oldDC = NULL;
|
||||
HGLRC hGLRC, oldRC = NULL;
|
||||
int format;
|
||||
int major, minor;
|
||||
const char* version;
|
||||
const GLubyte* (APIENTRY *sst_glGetString)(GLenum);
|
||||
SST_OpenGLContext_Win32* ctx;
|
||||
BYTE rgb[3] = { 1, 1, 1 };
|
||||
|
||||
/* No multisample support, but 2x or greater MSAA requested -> fail */
|
||||
if(attribs->multisampleFactor > 1)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate a GL context */
|
||||
ctx = (SST_OpenGLContext_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(ctx == NULL)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get window DC */
|
||||
hWnd = createTmpWindow(displayTarget);
|
||||
hDC = GetDC(hWnd);
|
||||
|
||||
/* We can't do MSAA at all, though */
|
||||
if(attribs->multisampleFactor > 1)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Figure out how to set up color bits. These are minimums. MSDN states that they
|
||||
are "Not used", but be safe anyways. */
|
||||
if(attribs->colorBits == 24)
|
||||
{
|
||||
rgb[0] = rgb[1] = rgb[2] = 8;
|
||||
}
|
||||
else if(attribs->colorBits == 16 || attribs->colorBits == 15)
|
||||
{
|
||||
/* 555 or 565 color. Set all to 5 since "minimum" of 5 allows for 565 too */
|
||||
rgb[0] = rgb[1] = rgb[2] = 5;
|
||||
}
|
||||
|
||||
/* Initialize the PFD */
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | (attribs->stereoEnabled? PFD_STEREO : 0);
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = attribs->colorBits;
|
||||
pfd.cAlphaBits = attribs->alphaBits;
|
||||
pfd.cRedBits = rgb[0];
|
||||
pfd.cGreenBits = rgb[1];
|
||||
pfd.cBlueBits = rgb[2];
|
||||
pfd.cDepthBits = attribs->depthBits;
|
||||
pfd.cStencilBits = attribs->stencilBits;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
/* Get a compatiable pixel format */
|
||||
format = ChoosePixelFormat(hDC, &pfd);
|
||||
if(format == 0)
|
||||
{
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get info about the pixel format we're using */
|
||||
if(selectedAttribsReturn != NULL)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR spfd;
|
||||
DescribePixelFormat(hDC, format, sizeof(spfd), &spfd);
|
||||
|
||||
selectedAttribsReturn->alphaBits = pfd.cAlphaBits;
|
||||
selectedAttribsReturn->colorBits = pfd.cColorBits;
|
||||
selectedAttribsReturn->contextVersionMajor = 0;
|
||||
selectedAttribsReturn->contextVersionMinor = 0;
|
||||
selectedAttribsReturn->depthBits = pfd.cDepthBits;
|
||||
selectedAttribsReturn->multisampleFactor = 1;
|
||||
selectedAttribsReturn->stencilBits = pfd.cStencilBits;
|
||||
selectedAttribsReturn->stereoEnabled = (pfd.dwFlags & PFD_STEREO);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Set the pixel format for the device */
|
||||
if(!SetPixelFormat(hDC, format, &pfd))
|
||||
{
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the GL context */
|
||||
hGLRC = wgl->CreateContext(hDC);
|
||||
if(hGLRC == NULL)
|
||||
{
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Activate the context to see if correct version was set */
|
||||
oldDC = wgl->GetCurrentDC();
|
||||
oldRC = wgl->GetCurrentContext();
|
||||
if(!wgl->MakeCurrent(hDC, hGLRC))
|
||||
{
|
||||
wgl->DeleteContext(hGLRC);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Resolve glGetString() and call it to check version number matching */
|
||||
sst_glGetString = (const GLubyte* (APIENTRY*)(GLenum name))GetProcAddress(opengl32, "glGetString");
|
||||
version = (const char*)sst_glGetString(GL_VERSION);
|
||||
major = (int)(version[0] - '0'); /* "X.Y" -> [0]:major, [2]:minor */
|
||||
minor = (int)(version[2] - '0');
|
||||
|
||||
/* Got version info. Detach our context, restore old one */
|
||||
wgl->MakeCurrent(oldDC, oldRC);
|
||||
|
||||
/* Save context version information */
|
||||
if(selectedAttribsReturn != NULL)
|
||||
{
|
||||
selectedAttribsReturn->contextVersionMajor = (uint8_t)major;
|
||||
selectedAttribsReturn->contextVersionMinor = (uint8_t)minor;
|
||||
}
|
||||
|
||||
/* If the major version is too low or the major version is OK, but the minor version is lacking, then fail */
|
||||
if(major < attribs->contextVersionMajor ||
|
||||
(major == attribs->contextVersionMajor && minor < attribs->contextVersionMinor))
|
||||
{
|
||||
wgl->DeleteContext(hGLRC);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
|
||||
ctx->displayTarget = displayTarget;
|
||||
ctx->hSlaveWnd = NULL;
|
||||
ctx->hDCActive = NULL;
|
||||
ctx->opengl32 = opengl32;
|
||||
ctx->wgl = *wgl;
|
||||
ctx->pixelFormat = format;
|
||||
ctx->context = hGLRC;
|
||||
ctx->isLegacy = TRUE;
|
||||
ctx->ctxVersion[0] = (short)major;
|
||||
ctx->ctxVersion[1] = (short)minor;
|
||||
ctx->legacyEnabled = FALSE; /* These refer to profiles in GL >= 3.x contexts. Here they are meaningless, so set to false */
|
||||
ctx->debugEnabled = FALSE;
|
||||
|
||||
return (SST_OpenGLContext)ctx;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int modernChoosePixelFormat(HDC hDC, WGLFunctions* wgl, const SST_OpenGLContextAttributes* attribs)
|
||||
{
|
||||
int attrs[MAX_GL_ATTRS];
|
||||
int format;
|
||||
int* ptr = attrs;
|
||||
UINT nrFormats;
|
||||
BOOL ok;
|
||||
|
||||
|
||||
/* Set up basic attributes */
|
||||
ptr = addAttr(ptr, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE);
|
||||
ptr = addAttr(ptr, WGL_SUPPORT_OPENGL_ARB, GL_TRUE);
|
||||
ptr = addAttr(ptr, WGL_DOUBLE_BUFFER_ARB, GL_TRUE);
|
||||
ptr = addAttr(ptr, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
|
||||
ptr = addAttr(ptr, WGL_COLOR_BITS_ARB, attribs->colorBits);
|
||||
ptr = addAttr(ptr, WGL_ALPHA_BITS_ARB, attribs->alphaBits);
|
||||
ptr = addAttr(ptr, WGL_DEPTH_BITS_ARB, attribs->depthBits);
|
||||
ptr = addAttr(ptr, WGL_STENCIL_BITS_ARB, attribs->stencilBits);
|
||||
ptr = addAttr(ptr, WGL_STEREO_ARB, attribs->stereoEnabled ? GL_TRUE : GL_FALSE); /* Must be GL_TRUE || GL_FALSE, not just "non-zero" */
|
||||
|
||||
/* Multisampling requested? */
|
||||
if(attribs->multisampleFactor > 1)
|
||||
{
|
||||
/* Is it supported? */
|
||||
if(wgl->supportsMultisample)
|
||||
{
|
||||
ptr = addAttr(ptr, WGL_SAMPLE_BUFFERS_ARB, 1);
|
||||
ptr = addAttr(ptr, WGL_SAMPLES_ARB, attribs->multisampleFactor);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
*ptr = 0;
|
||||
|
||||
nrFormats = 0;
|
||||
/* Attempt to get pixel formats that match ours */
|
||||
ok = wgl->ChoosePixelFormatARB(hDC, attrs, NULL, 1, &format, &nrFormats);
|
||||
|
||||
/* This can return success with 0 formats, so check if it was actually "successful" in finding > 0 formats */
|
||||
if(!ok || nrFormats == 0)
|
||||
return 0;
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void modernGetPixelInfo(HDC hDC, int format, WGLFunctions* wgl, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
int attrs[8];
|
||||
int values[8] = { 0 };
|
||||
int attrCount;
|
||||
|
||||
attrs[0] = WGL_COLOR_BITS_ARB;
|
||||
attrs[1] = WGL_ALPHA_BITS_ARB;
|
||||
attrs[2] = WGL_DEPTH_BITS_ARB;
|
||||
attrs[3] = WGL_STENCIL_BITS_ARB;
|
||||
attrs[4] = WGL_STEREO_ARB;
|
||||
attrs[5] = WGL_SAMPLE_BUFFERS_ARB;
|
||||
|
||||
/* Check multisample */
|
||||
attrCount = (wgl->supportsMultisample ? 6 : 5);
|
||||
|
||||
|
||||
wgl->GetPixelFormatAttribivARB(hDC, format, 0, attrCount, attrs, values);
|
||||
|
||||
|
||||
selectedAttribsReturn->colorBits = (uint8_t)values[0];
|
||||
selectedAttribsReturn->alphaBits = (uint8_t)values[1];
|
||||
selectedAttribsReturn->depthBits = (uint8_t)values[2];
|
||||
selectedAttribsReturn->stencilBits = (uint8_t)values[3];
|
||||
selectedAttribsReturn->stereoEnabled = (uint8_t)values[4];
|
||||
if(wgl->supportsMultisample)
|
||||
selectedAttribsReturn->multisampleFactor = (uint8_t)values[5];
|
||||
else
|
||||
selectedAttribsReturn->multisampleFactor = 1;
|
||||
|
||||
}
|
||||
|
||||
const struct SST_WM_OpenGLFuncs Win32_OpenGLFuncs = {
|
||||
Win32_CreateOpenGLContext,
|
||||
Win32_CreateSlaveOpenGLContext,
|
||||
Win32_SwapOpenGLBuffers,
|
||||
Win32_BindOpenGLContext,
|
||||
Win32_DestroyOpenGLContext
|
||||
};
|
||||
97
libsst-wm/Win32/SST_WMRender_Win32.c
Normal file
97
libsst-wm/Win32/SST_WMRender_Win32.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
SST_WMRender_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 9/19/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Software rendering support (Win32)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
#include <SST/SST_WMWindow.h>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_EnableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
HDC hDC;
|
||||
HDC hDCTmp;
|
||||
HBITMAP hBMP;
|
||||
RECT r;
|
||||
|
||||
hDCTmp = GetDC(win->hWnd);
|
||||
hDC = CreateCompatibleDC(hDCTmp);
|
||||
|
||||
if(GetDeviceCaps(hDCTmp, BITSPIXEL) != 32)
|
||||
{
|
||||
DeleteDC(hDC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GetClientRect(win->hWnd, &r);
|
||||
|
||||
hBMP = CreateCompatibleBitmap(hDCTmp, r.right, r.bottom);
|
||||
SelectObject(hDC, hBMP);
|
||||
|
||||
ReleaseDC(win->hWnd, hDCTmp);
|
||||
|
||||
win->softwareDC = hDC;
|
||||
win->softwareImage = hBMP;
|
||||
win->softwareBackbuffer = HeapAlloc(GetProcessHeap(), 0, (SIZE_T)r.right * (SIZE_T)r.bottom * 4);
|
||||
win->softwarePitch = r.right * 4;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DisableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
if(win->softwareBackbuffer)
|
||||
HeapFree(GetProcessHeap(), 0, win->softwareBackbuffer);
|
||||
if(win->softwareDC)
|
||||
DeleteDC(win->softwareDC);
|
||||
if(win->softwareImage)
|
||||
DeleteObject(win->softwareImage);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void* Win32_LockBackbuffer(SST_Window window, size_t* pitchReturn)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
*pitchReturn = win->softwarePitch;
|
||||
|
||||
return win->softwareBackbuffer;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_UnlockBackbuffer(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
InvalidateRect(win->hWnd, NULL, FALSE);
|
||||
UpdateWindow(win->hWnd);
|
||||
}
|
||||
|
||||
struct SST_WM_RenderFuncs Win32_RenderFuncs = {
|
||||
Win32_EnableSoftwareRendering,
|
||||
Win32_DisableSoftwareRendering,
|
||||
Win32_LockBackbuffer,
|
||||
Win32_UnlockBackbuffer
|
||||
};
|
||||
72
libsst-wm/Win32/SST_WMVideoMode_Win32.c
Normal file
72
libsst-wm/Win32/SST_WMVideoMode_Win32.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
SST_WMVideoMode_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/26/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Video mode setting functions
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode)
|
||||
{
|
||||
DEVMODEA devMode;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
const DISPLAY_DEVICEA* dev = &displayTarget->devs[screenIndex];
|
||||
|
||||
memset(&devMode, 0, sizeof(devMode));
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
devMode.dmBitsPerPel = vmode->bpp;
|
||||
devMode.dmPelsWidth = vmode->width;
|
||||
devMode.dmPelsHeight = vmode->height;
|
||||
devMode.dmDisplayFrequency = vmode->refreshRate;
|
||||
devMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
|
||||
|
||||
return (ChangeDisplaySettingsExA(dev->DeviceName, &devMode, NULL, CDS_FULLSCREEN, NULL) == DISP_CHANGE_SUCCESSFUL);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
const DISPLAY_DEVICEA* dev = &displayTarget->devs[screenIndex];
|
||||
DEVMODEA devMode;
|
||||
int ok = 0;
|
||||
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
|
||||
if(EnumDisplaySettingsA(dev->DeviceName, ENUM_CURRENT_SETTINGS, &devMode))
|
||||
{
|
||||
vmodeReturn->bpp = devMode.dmBitsPerPel;
|
||||
vmodeReturn->width = devMode.dmPelsWidth;
|
||||
vmodeReturn->height = devMode.dmPelsHeight;
|
||||
vmodeReturn->refreshRate = devMode.dmDisplayFrequency;
|
||||
|
||||
if(vmodeReturn->refreshRate == 1)
|
||||
vmodeReturn->refreshRate = SST_DEFAULT_REFRESHRATE;
|
||||
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
const struct SST_WM_VideoModeFuncs Win32_VideoModeFuncs = {
|
||||
Win32_SetVideoModeOnScreen,
|
||||
Win32_GetVideoModeOnScreen
|
||||
};
|
||||
667
libsst-wm/Win32/SST_WMWindow_Win32.c
Normal file
667
libsst-wm/Win32/SST_WMWindow_Win32.c
Normal file
@@ -0,0 +1,667 @@
|
||||
/*
|
||||
SST_WMWindow_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/1/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Window creation (Win32)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMWindow.h>
|
||||
#include "Win32Private.h"
|
||||
#include "../EventQueue.h"
|
||||
#include "../APIPrivate.h"
|
||||
|
||||
static LONG regRefCount = 0;
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Win32_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead)
|
||||
{
|
||||
DISPLAY_DEVICEA* devs;
|
||||
size_t devCount;
|
||||
SST_DisplayTarget_Win32* displayTarget;
|
||||
|
||||
|
||||
/* Get Win32 devices */
|
||||
devs = get_win32devs(&devCount);
|
||||
if(devs == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Filter the list */
|
||||
devCount = filter_win32devs(devs, devCount, adapterIndex);
|
||||
if(devCount == 0)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Not doing multihead? */
|
||||
if(screenIndexOrMultihead != SST_MULTIHEAD)
|
||||
{
|
||||
/* Does the screen index exceed the number of attached screens? */
|
||||
if(screenIndexOrMultihead >= devCount)
|
||||
{
|
||||
/* Failure */
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Allocate a display target structure */
|
||||
displayTarget = (SST_DisplayTarget_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_DisplayTarget_Win32));
|
||||
if(displayTarget == NULL)
|
||||
{
|
||||
/* Failure */
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize user event queue */
|
||||
if(!InitEQ(&displayTarget->userEventQueue))
|
||||
{
|
||||
/* Failure */
|
||||
HeapFree(GetProcessHeap(), 0, displayTarget);
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
InitializeCriticalSection(&displayTarget->userEventLock);
|
||||
displayTarget->devs = devs;
|
||||
displayTarget->screenCount = devCount;
|
||||
displayTarget->screenIndex = screenIndexOrMultihead;
|
||||
displayTarget->firstWindow = NULL;
|
||||
displayTarget->relativeMouse = FALSE;
|
||||
|
||||
/* Register class if the refcount == 1 */
|
||||
if(InterlockedIncrement(®RefCount) == 1)
|
||||
{
|
||||
WNDCLASSEXA wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpszClassName = SST_WINCLASS;
|
||||
wc.hInstance = GetModuleHandleA(NULL);
|
||||
wc.lpfnWndProc = libsstWndProc;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.hbrBackground = (HBRUSH)(uintptr_t)(COLOR_WINDOW+1);
|
||||
RegisterClassExA(&wc);
|
||||
}
|
||||
|
||||
return (SST_DisplayTarget)displayTarget;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static size_t Win32_GetDisplayTargetScreenCount(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
|
||||
/*
|
||||
Multihead -> real screen count
|
||||
Otherwise -> 1
|
||||
*/
|
||||
if(displayTarget->screenIndex == SST_MULTIHEAD)
|
||||
return displayTarget->screenCount;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_Window Win32_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title)
|
||||
{
|
||||
RECT r;
|
||||
DWORD style, styleEx;
|
||||
HWND hWnd;
|
||||
SST_Window_Win32* win;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
FindMonitorInfo fmi;
|
||||
|
||||
/* Attempt to find the monitor associated with a display device */
|
||||
findMonitor(&displayTarget->devs[screenIndex], &fmi);
|
||||
|
||||
/* Didn't find it? */
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Allocate SST window structure */
|
||||
win = (SST_Window_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_Window_Win32));
|
||||
if(win == NULL)
|
||||
return NULL;
|
||||
|
||||
win->owner = displayTarget;
|
||||
win->next = displayTarget->firstWindow;
|
||||
win->owner = displayTarget;
|
||||
win->isFullscreen = FALSE;
|
||||
win->setPixelFormat = FALSE;
|
||||
win->softwareBackbuffer = NULL;
|
||||
win->softwareDC = NULL;
|
||||
win->softwareImage = NULL;
|
||||
win->softwarePitch = 0;
|
||||
|
||||
/* These styles may be useful later.
|
||||
DWORD style = (Fullscreen ? WS_POPUP : WS_CAPTION | WS_SYSMENU);
|
||||
DWORD styleEx = (Multihead2ndWindow? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW);
|
||||
*/
|
||||
style = WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
|
||||
styleEx = WS_EX_APPWINDOW;
|
||||
|
||||
/* Start the window relative to those coordinates */
|
||||
r.top = 0;
|
||||
r.left = 0;
|
||||
r.bottom = (LONG)height;
|
||||
r.right = (LONG)width;
|
||||
AdjustWindowRectEx(&r, style, FALSE, styleEx);
|
||||
|
||||
if(r.top != 0)
|
||||
{
|
||||
LONG d = -r.top;
|
||||
|
||||
r.top = 0;
|
||||
r.bottom += d;
|
||||
}
|
||||
if(r.left != 0)
|
||||
{
|
||||
LONG d = -r.left;
|
||||
|
||||
r.left = 0;
|
||||
r.right += d;
|
||||
}
|
||||
|
||||
r.top += fmi.top + (LONG)y;
|
||||
r.left += fmi.left + (LONG)x;
|
||||
r.bottom += r.top;
|
||||
r.right += r.left;
|
||||
|
||||
|
||||
hWnd = CreateWindowExA(
|
||||
styleEx,
|
||||
SST_WINCLASS,
|
||||
title,
|
||||
style,
|
||||
r.left, r.top, /* XY position */
|
||||
r.right-r.left, r.bottom-r.top, /* Position */
|
||||
NULL, /* parent window */
|
||||
NULL, GetModuleHandleA(NULL), win);
|
||||
|
||||
/* Failed to create window */
|
||||
if(hWnd == NULL)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, win);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save window info */
|
||||
win->hWnd = hWnd;
|
||||
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
|
||||
/* Link window as new root */
|
||||
displayTarget->firstWindow = win;
|
||||
|
||||
return (SST_Window)win;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Win32_GetWindowDisplayTarget(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
return win->owner;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SetWindowText(SST_Window window, const char* titleBar)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
SetWindowTextA(win->hWnd, titleBar);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetWindowRect(SST_Window window, SST_Rect* rectReturn)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
MONITORINFO info;
|
||||
RECT rectClient;
|
||||
RECT rectWin;
|
||||
|
||||
/* Get info about the monitor the window is on */
|
||||
info.cbSize = sizeof(info);
|
||||
if(!GetMonitorInfoA(MonitorFromWindow(win->hWnd, MONITOR_DEFAULTTONEAREST), &info))
|
||||
return;
|
||||
|
||||
/* This returns (0,0) - (w,h). I don't know why they bother using a RECT instead
|
||||
of a POINT structure, since the top/left is always (0,0). */
|
||||
GetClientRect(win->hWnd, &rectClient);
|
||||
|
||||
GetWindowRect(win->hWnd, &rectWin);
|
||||
|
||||
rectReturn->x = (uint32_t)(rectWin.left - info.rcMonitor.left);
|
||||
rectReturn->y = (uint32_t)(rectWin.top - info.rcMonitor.top);
|
||||
rectReturn->width = (uint32_t)rectClient.right;
|
||||
rectReturn->height = (uint32_t)rectClient.bottom;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y)
|
||||
{
|
||||
FindMonitorInfo fmi;
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
SST_DisplayTarget_Win32* displayTarget = win->owner;
|
||||
int px, py;
|
||||
|
||||
if(screenIndex != SST_SAME_SCREEN)
|
||||
{
|
||||
/* Atttempt to find the monitor associated with a display device */
|
||||
findMonitor(&displayTarget->devs[screenIndex], &fmi);
|
||||
|
||||
/* Didn't find it? (monitor unplugged?) */
|
||||
if(!fmi.foundIt)
|
||||
return;
|
||||
|
||||
/* New position = monitor base + offset */
|
||||
px = (int)x + (int)fmi.top;
|
||||
py = (int)y + (int)fmi.left;
|
||||
}
|
||||
else /* Move relative to the same screen */
|
||||
{
|
||||
MONITORINFO info;
|
||||
|
||||
/* Get info about the monitor the window is on */
|
||||
info.cbSize = sizeof(info);
|
||||
if(!GetMonitorInfoA(MonitorFromWindow(win->hWnd, MONITOR_DEFAULTTONEAREST), &info))
|
||||
return;
|
||||
|
||||
px = (int)x + (int)info.rcMonitor.left;
|
||||
py = (int)y + (int)info.rcMonitor.top;
|
||||
}
|
||||
|
||||
SetWindowPos(win->hWnd, NULL,
|
||||
px, py,
|
||||
0, 0,
|
||||
SWP_NOOWNERZORDER | SWP_NOSIZE);
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_ResizeWindow(SST_Window window, uint32_t width, uint32_t height)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
RECT r;
|
||||
BOOL hasMenu;
|
||||
HWND hParent;
|
||||
|
||||
/* Get the client & window rect */
|
||||
GetClientRect(win->hWnd, &r);
|
||||
|
||||
r.right = r.left + (LONG)width;
|
||||
r.bottom = r.top + (LONG)height;
|
||||
|
||||
hParent = (HWND)GetWindowLongPtrA(win->hWnd, GWLP_HWNDPARENT);
|
||||
if(hParent == NULL)
|
||||
hasMenu = (GetMenu(win->hWnd) != NULL);
|
||||
else
|
||||
hasMenu = FALSE;
|
||||
|
||||
|
||||
AdjustWindowRectEx(&r, GetWindowLongA(win->hWnd, GWL_STYLE), hasMenu, GetWindowLongA(win->hWnd, GWL_EXSTYLE));
|
||||
|
||||
SetWindowPos(win->hWnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOOWNERZORDER | SWP_NOMOVE);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTWS_SHOWN:
|
||||
{
|
||||
int cmd;
|
||||
if(param == 0)
|
||||
cmd = SW_HIDE;
|
||||
else
|
||||
cmd = SW_SHOW;
|
||||
|
||||
ShowWindow(win->hWnd, cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Turn on/off resizeability */
|
||||
case SSTWS_RESIZEABLE:
|
||||
{
|
||||
DWORD style;
|
||||
RECT rect;
|
||||
POINT tl, br;
|
||||
|
||||
/* Get info about the window */
|
||||
style = GetWindowLongA(win->hWnd, GWL_STYLE);
|
||||
GetClientRect(win->hWnd, &rect);
|
||||
|
||||
tl.x = rect.left;
|
||||
tl.y = rect.top;
|
||||
|
||||
br.x = rect.right;
|
||||
br.y = rect.bottom;
|
||||
|
||||
ClientToScreen(win->hWnd, &tl);
|
||||
ClientToScreen(win->hWnd, &br);
|
||||
|
||||
rect.left = tl.x;
|
||||
rect.top = tl.y;
|
||||
rect.right = br.x;
|
||||
rect.bottom = br.y;
|
||||
|
||||
|
||||
if(param == 0)
|
||||
style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
|
||||
else
|
||||
style |= (WS_THICKFRAME | WS_MAXIMIZEBOX);
|
||||
|
||||
AdjustWindowRectEx(&rect, style, (GetMenu(win->hWnd) ? TRUE : FALSE), GetWindowLongA(win->hWnd, GWL_EXSTYLE));
|
||||
SetWindowLongA(win->hWnd, GWL_STYLE, (LONG)style);
|
||||
|
||||
/* MSDN: "Certain window data is cached, so changes you make using SetWindowLong() will not take effect until you
|
||||
call the SetWindowPos() function." So, let's update it... */
|
||||
SetWindowPos(win->hWnd, NULL,
|
||||
rect.left, rect.top,
|
||||
rect.right - rect.left,
|
||||
rect.bottom - rect.top,
|
||||
SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_FULLSCREEN:
|
||||
{
|
||||
DWORD style;
|
||||
|
||||
/* Enabling fullscreen? */
|
||||
if(param && !win->isFullscreen)
|
||||
{
|
||||
MONITORINFO info;
|
||||
RECT r;
|
||||
POINT pt;
|
||||
|
||||
/* Get current window style */
|
||||
style = GetWindowLongA(win->hWnd, GWL_STYLE);
|
||||
|
||||
/* Save info about the window so when we exit fullscreen, we're good */
|
||||
win->wp.length = sizeof(win->wp);
|
||||
GetWindowPlacement(win->hWnd, &win->wp);
|
||||
GetWindowRect(win->hWnd, &r);
|
||||
pt.x = r.top;
|
||||
pt.y = r.left;
|
||||
|
||||
|
||||
|
||||
/* Get info about the monitor the window is on */
|
||||
info.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST), &info);
|
||||
|
||||
/* Remove title bar, caption, etc. */
|
||||
SetWindowLong(win->hWnd, GWL_STYLE, style & (~WS_OVERLAPPEDWINDOW));
|
||||
|
||||
/* Move & resize to cover entire screen */
|
||||
SetWindowPos(win->hWnd, HWND_TOP,
|
||||
(int)info.rcMonitor.left, (int)info.rcMonitor.top, /* Position window in the top-left corner */
|
||||
(int)(info.rcMonitor.right - info.rcMonitor.left), /* Width = width of monitor */
|
||||
(int)(info.rcMonitor.bottom - info.rcMonitor.top), /* Height = height of monitor */
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED); /* Don't change*/
|
||||
|
||||
|
||||
win->isFullscreen = TRUE;
|
||||
}
|
||||
else if(win->isFullscreen) /* Disabling fullscreen */
|
||||
{
|
||||
style = GetWindowLongA(win->hWnd, GWL_STYLE);
|
||||
SetWindowLong(win->hWnd, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
|
||||
|
||||
/* Restore old window placement */
|
||||
SetWindowPlacement(win->hWnd, &win->wp);
|
||||
SetWindowPos(win->hWnd, NULL, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
|
||||
win->isFullscreen = FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_MINIMIZED:
|
||||
{
|
||||
int cmd;
|
||||
if(param == 0)
|
||||
{
|
||||
SST_WMEvent* event;
|
||||
cmd = SW_RESTORE;
|
||||
|
||||
/* Win32 doesn't send a restore message if pragmatically restored, so do it ourselves */
|
||||
event = AllocSlotInEQ(&win->eventQueue);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_RESTORED;
|
||||
memset(&event->details, 0, sizeof(event->details));
|
||||
}
|
||||
}
|
||||
else
|
||||
cmd = SW_MINIMIZE;
|
||||
|
||||
ShowWindow(win->hWnd, cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTDTS_RELMOUSE:
|
||||
{
|
||||
RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
|
||||
|
||||
/* Disabling? */
|
||||
if(displayTarget->relativeMouse && param == 0)
|
||||
{
|
||||
rawMouse.dwFlags |= RIDEV_REMOVE;
|
||||
|
||||
/* Attempt to unregister raw mouse. If successful, set 'relativeMouse' to FALSE */
|
||||
if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)))
|
||||
{
|
||||
displayTarget->relativeMouse = FALSE;
|
||||
ClipCursor(NULL);
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
}
|
||||
else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */
|
||||
{
|
||||
if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)))
|
||||
{
|
||||
HWND active;
|
||||
SST_Window_Win32* win;
|
||||
|
||||
displayTarget->relativeMouse = TRUE;
|
||||
ShowCursor(FALSE);
|
||||
|
||||
/* Decide if this window belows to any in this display target, if so, lock cursor into it */
|
||||
active = GetActiveWindow();
|
||||
win = displayTarget->firstWindow;
|
||||
|
||||
while(win)
|
||||
{
|
||||
/* It does belong to this display target, so lock it into place */
|
||||
if(win->hWnd == active)
|
||||
{
|
||||
LONG cx, cy;
|
||||
RECT rect;
|
||||
|
||||
GetWindowRect(win->hWnd, &rect);
|
||||
cx = (rect.left + rect.right) / 2;
|
||||
cy = (rect.top + rect.bottom) / 2;
|
||||
|
||||
/* Ensure cursor cannot leave the center of the window */
|
||||
rect.left = cx-1;
|
||||
rect.right = cx+1;
|
||||
rect.top = cy-1;
|
||||
rect.bottom = cy+1;
|
||||
ClipCursor(&rect);
|
||||
break;
|
||||
}
|
||||
else
|
||||
win = win->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyWindow(SST_Window window)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget;
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
SST_Window_Win32* nextWin;
|
||||
|
||||
displayTarget = win->owner;
|
||||
nextWin = displayTarget->firstWindow;
|
||||
|
||||
/* Special case: root window */
|
||||
if(nextWin == win)
|
||||
{
|
||||
/* Set new root to be this->next */
|
||||
displayTarget->firstWindow = win->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
/* Check list */
|
||||
while(nextWin)
|
||||
{
|
||||
/* Did we find the window? */
|
||||
if(nextWin->next == win)
|
||||
{
|
||||
/* Remove this window from the linked list */
|
||||
nextWin->next = win->next;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
nextWin = nextWin->next;
|
||||
}
|
||||
|
||||
/* Don't destroy another display target's window */
|
||||
if(!found)
|
||||
return;
|
||||
|
||||
}
|
||||
/* Actually destroy the Win32 window */
|
||||
DestroyWindow(win->hWnd);
|
||||
|
||||
if(win->softwareBackbuffer)
|
||||
HeapFree(GetProcessHeap(), 0, win->softwareBackbuffer);
|
||||
if(win->softwareDC)
|
||||
DeleteDC(win->softwareDC);
|
||||
if(win->softwareImage)
|
||||
DeleteObject(win->softwareImage);
|
||||
|
||||
|
||||
/* TODO empty message queue? */
|
||||
|
||||
/* Free the window */
|
||||
HeapFree(GetProcessHeap(), 0, win);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyDisplayTarget(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
SST_Window_Win32* window = displayTarget->firstWindow;
|
||||
|
||||
/* Destroy all windows */
|
||||
while(window)
|
||||
{
|
||||
/* Save the next window */
|
||||
SST_Window_Win32* next = window->next;
|
||||
|
||||
/* Actually destroy the Win32 window handle */
|
||||
DestroyWindow(window->hWnd);
|
||||
HeapFree(GetProcessHeap(), 0, window);
|
||||
|
||||
/*
|
||||
TODO: should we empty the message queue of all messages owned by this window? Do
|
||||
they automatically get removed? Aiiyeeee!
|
||||
*/
|
||||
|
||||
/* Move to next window */
|
||||
window = next;
|
||||
}
|
||||
|
||||
/* Delete user event queue lock */
|
||||
DeleteCriticalSection(&displayTarget->userEventLock);
|
||||
|
||||
|
||||
/* Free structures */
|
||||
DestroyEQ(&displayTarget->userEventQueue);
|
||||
HeapFree(GetProcessHeap(), 0, displayTarget->devs);
|
||||
HeapFree(GetProcessHeap(), 0, displayTarget);
|
||||
|
||||
/* Unregister */
|
||||
if(InterlockedDecrement(®RefCount) == 0)
|
||||
UnregisterClassA(SST_WINCLASS, GetModuleHandleA(NULL));
|
||||
}
|
||||
|
||||
extern int Win32_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons);
|
||||
|
||||
const struct SST_WM_WindowFuncs Win32_WindowFuncs = {
|
||||
Win32_CreateDisplayTarget,
|
||||
Win32_GetDisplayTargetScreenCount,
|
||||
Win32_CreateWindowOnScreen,
|
||||
Win32_GetWindowDisplayTarget,
|
||||
Win32_SetWindowText,
|
||||
Win32_GetWindowRect,
|
||||
Win32_MoveWindowOnScreen,
|
||||
Win32_ResizeWindow,
|
||||
Win32_ShowDialogBox,
|
||||
Win32_SetWindowState,
|
||||
Win32_SetDisplayTargetState,
|
||||
Win32_DestroyWindow,
|
||||
Win32_DestroyDisplayTarget
|
||||
};
|
||||
62
libsst-wm/Win32/Win32Driver.c
Normal file
62
libsst-wm/Win32/Win32Driver.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Win32Driver.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 12/18/2014
|
||||
|
||||
Purpose:
|
||||
|
||||
Windows (Win32 API) driver for libsst-wm
|
||||
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#include "../APIPrivate.h"
|
||||
#include "Win32Private.h"
|
||||
|
||||
extern const struct SST_WM_WindowFuncs Win32_WindowFuncs;
|
||||
extern const struct SST_WM_EnumFuncs Win32_EnumFuncs;
|
||||
extern const struct SST_WM_EventFuncs Win32_EventFuncs;
|
||||
extern const struct SST_WM_OpenGLFuncs Win32_OpenGLFuncs;
|
||||
extern const struct SST_WM_RenderFuncs Win32_RenderFuncs;
|
||||
extern const struct SST_WM_VideoModeFuncs Win32_VideoModeFuncs;
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Win32_init()
|
||||
{
|
||||
if(getenv("LIBSST_NO_WIN32"))
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Win32_shutdown()
|
||||
{
|
||||
/* Nothing to do (now) */
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const struct SST_WM_Driver Win32Driver = {
|
||||
"Win32 Driver",
|
||||
Win32_init,
|
||||
Win32_shutdown,
|
||||
&Win32_WindowFuncs,
|
||||
&Win32_EnumFuncs,
|
||||
&Win32_EventFuncs,
|
||||
&Win32_OpenGLFuncs,
|
||||
&Win32_RenderFuncs,
|
||||
&Win32_VideoModeFuncs
|
||||
};
|
||||
1351
libsst-wm/Win32/Win32Private.c
Normal file
1351
libsst-wm/Win32/Win32Private.c
Normal file
File diff suppressed because it is too large
Load Diff
267
libsst-wm/Win32/Win32Private.h
Normal file
267
libsst-wm/Win32/Win32Private.h
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
Win32Private.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/7/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Private defintions and functions for Win32 implementation of libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32PRIVATE_H
|
||||
#define _WIN32PRIVATE_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h> /* More Win32 macros */
|
||||
#include <GL/gl.h>
|
||||
#include <SST/SST_WMTypes.h>
|
||||
#include "../EventQueue.h"
|
||||
|
||||
#define ADAPTER_NAME_STRLEN 128
|
||||
#define STRLEN_GUID ((size_t)64) /* Storage enough to hold a Win32 GUID if it was written as a string of hex characters with dashes (need only like 36-38) */
|
||||
#define MIN_BPP 24 /* Minimum BPP for a mode to be considered */
|
||||
#define SST_WINCLASS "libsstwm"
|
||||
#define SST_DLGCLASS "libsstwmdlg"
|
||||
#define MAX_GL_ATTRS 32
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef HGLRC (WINAPI * pf_wglCreateContext)(HDC hdc);
|
||||
typedef BOOL (WINAPI * pf_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
|
||||
typedef PROC (WINAPI * pf_wglGetProcAddress)(LPCSTR lpszProc);
|
||||
typedef BOOL (WINAPI * pf_wglDeleteContext)(HGLRC hglrc);
|
||||
typedef BOOL (WINAPI * pf_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
|
||||
typedef HGLRC (WINAPI * pf_wglGetCurrentContext)(void);
|
||||
typedef HDC (WINAPI * pf_wglGetCurrentDC)(void);
|
||||
typedef const char* (WINAPI * pf_wglGetExtensionsStringARB)(HDC hdc);
|
||||
typedef BOOL (WINAPI * pf_wglChoosePixelFormatARB)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
|
||||
typedef HGLRC (WINAPI * pf_wglCreateContextAttribsARB)(HDC hDC, HGLRC hshareContext, const int *attribList);
|
||||
typedef BOOL (WINAPI * pf_wglGetPixelFormatAttribivARB)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Note about memory management -- these functions all use the Win32 API (HeapAlloc()/HeapFree()) instead of the CRT functions (malloc()/free()).
|
||||
This is so that it has less of dependency on the CRT.
|
||||
*/
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Structure to maps an adapter-display pair to a DISPLAY_DEVICE */
|
||||
typedef struct ASMapEntry
|
||||
{
|
||||
SST_VideoMode defaultVmode;
|
||||
const DISPLAY_DEVICEA* dev;
|
||||
SST_VideoMode* vmodes;
|
||||
size_t adapter;
|
||||
size_t screen;
|
||||
size_t vmodeCount;
|
||||
} ASMapEntry;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct FindMonitorInfo
|
||||
{
|
||||
const DISPLAY_DEVICEA* dev; /* Name of the device we are trying to find a matching HMONITOR for */
|
||||
BOOL foundIt; /* Did we find it? */
|
||||
LONG top, left; /* Monitor corner (top,left) */
|
||||
LONG bottom, right;
|
||||
} FindMonitorInfo;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_GraphicsEnumerator_Win32
|
||||
{
|
||||
char* adapterNames;
|
||||
DISPLAY_DEVICEA* devsFound;
|
||||
size_t* screenCount;
|
||||
ASMapEntry* ASMap;
|
||||
|
||||
|
||||
size_t adapterCount;
|
||||
size_t devCount;
|
||||
size_t ASPairCount;
|
||||
} SST_GraphicsEnumerator_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_DisplayTarget_Win32
|
||||
{
|
||||
CRITICAL_SECTION userEventLock; /* Lock protection user events */
|
||||
EventQueue userEventQueue;
|
||||
DISPLAY_DEVICEA* devs; /* Array of devices representing this display target */
|
||||
struct SST_Window_Win32* firstWindow; /* First window in a list of windows */
|
||||
size_t screenCount;
|
||||
size_t screenIndex;
|
||||
BOOL relativeMouse;
|
||||
} SST_DisplayTarget_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_Window_Win32
|
||||
{
|
||||
WINDOWPLACEMENT wp;
|
||||
EventQueue eventQueue;
|
||||
struct SST_Window_Win32* next;
|
||||
SST_DisplayTarget_Win32* owner;
|
||||
HWND hWnd;
|
||||
BOOL isFullscreen;
|
||||
BOOL setPixelFormat; /* If TRUE, then SetPixelFormat() was called on this window */
|
||||
|
||||
|
||||
/* Software rendering support */
|
||||
HBITMAP softwareImage;
|
||||
HDC softwareDC;
|
||||
void* softwareBackbuffer;
|
||||
size_t softwarePitch;
|
||||
|
||||
} SST_Window_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct WGLFunctions
|
||||
{
|
||||
pf_wglCreateContext CreateContext;
|
||||
pf_wglMakeCurrent MakeCurrent;
|
||||
pf_wglGetProcAddress GetProcAddress;
|
||||
pf_wglDeleteContext DeleteContext;
|
||||
pf_wglShareLists ShareLists;
|
||||
pf_wglGetCurrentContext GetCurrentContext;
|
||||
pf_wglGetCurrentDC GetCurrentDC;
|
||||
|
||||
/* WGL Extensions */
|
||||
pf_wglGetExtensionsStringARB GetExtensionsStringARB;
|
||||
pf_wglChoosePixelFormatARB ChoosePixelFormatARB;
|
||||
pf_wglCreateContextAttribsARB CreateContextAttribsARB;
|
||||
pf_wglGetPixelFormatAttribivARB GetPixelFormatAttribivARB;
|
||||
|
||||
BOOL supportsProfiles;
|
||||
BOOL supportsMultisample;
|
||||
} WGLFunctions;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_OpenGLContext_Win32
|
||||
{
|
||||
WGLFunctions wgl;
|
||||
SST_DisplayTarget_Win32* displayTarget;
|
||||
HMODULE opengl32;
|
||||
HGLRC context;
|
||||
HDC hDCActive;
|
||||
HWND hSlaveWnd; /* Slave contexts use a dummy window. Regular (master) GL contexts have this as NULL */
|
||||
int pixelFormat;
|
||||
short ctxVersion[2]; /* context version major/minor */
|
||||
BOOL isLegacy; /* Did we use legacy context creation functions? */
|
||||
BOOL legacyEnabled; /* Did we use legacy OpenGL (< 3.0) context support? */
|
||||
BOOL debugEnabled; /* Did we use debug OpenGL context support? */
|
||||
} SST_OpenGLContext_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
DISPLAY_DEVICEA* get_win32devs(size_t* devCountReturn);
|
||||
|
||||
char* get_adapters(const DISPLAY_DEVICEA* devsFound, size_t devCount, size_t* adapterCountReturn, char** adapterGUIDReturn);
|
||||
|
||||
/*
|
||||
Filter a list of Win32 devices in-place; modify list so that only relevant Win32 devices are returned.
|
||||
For example, if there are 3 devices: { Gpu0Screen0, Gpu1Screen0, Gpu1Screen1}, and adapterIndex == 1,
|
||||
then this returns { Gpu1Screen0, Gpu1Screen1 } in place. The number of devices in the filtered list are
|
||||
returned (in the example, 2).
|
||||
*/
|
||||
size_t filter_win32devs(DISPLAY_DEVICEA* devsFound, size_t devCount, size_t adapterIndex);
|
||||
|
||||
ASMapEntry* build_asmap(const DISPLAY_DEVICEA* devsFound, const char* adapterGUIDs, size_t devCount, size_t adapterCount, size_t* screenCount, size_t* mapSizeReturn);
|
||||
|
||||
SST_VideoMode* get_vmodes(const DISPLAY_DEVICEA* dev, size_t* modeCountReturn, SST_VideoMode* defaultMode);
|
||||
|
||||
LRESULT WINAPI libsstWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void resolveWGLSymbols(HMODULE opengl32, WGLFunctions* wgl);
|
||||
void resolveWGLExtSymbols(HDC hDC, WGLFunctions* wgl);
|
||||
|
||||
void findMonitor(const DISPLAY_DEVICEA* dev, FindMonitorInfo* fmi);
|
||||
|
||||
/* WGL_ARB_multisample */
|
||||
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
|
||||
#define WGL_SAMPLES_ARB 0x2042
|
||||
|
||||
/* WGL_ARB_pixel_format */
|
||||
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
|
||||
#define WGL_ACCELERATION_ARB 0x2003
|
||||
#define WGL_NEED_PALETTE_ARB 0x2004
|
||||
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
|
||||
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
|
||||
#define WGL_SWAP_METHOD_ARB 0x2007
|
||||
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
|
||||
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
|
||||
#define WGL_TRANSPARENT_ARB 0x200A
|
||||
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
|
||||
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
|
||||
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
|
||||
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
|
||||
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
|
||||
#define WGL_SHARE_DEPTH_ARB 0x200C
|
||||
#define WGL_SHARE_STENCIL_ARB 0x200D
|
||||
#define WGL_SHARE_ACCUM_ARB 0x200E
|
||||
#define WGL_SUPPORT_GDI_ARB 0x200F
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_STEREO_ARB 0x2012
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_RED_BITS_ARB 0x2015
|
||||
#define WGL_RED_SHIFT_ARB 0x2016
|
||||
#define WGL_GREEN_BITS_ARB 0x2017
|
||||
#define WGL_GREEN_SHIFT_ARB 0x2018
|
||||
#define WGL_BLUE_BITS_ARB 0x2019
|
||||
#define WGL_BLUE_SHIFT_ARB 0x201A
|
||||
#define WGL_ALPHA_BITS_ARB 0x201B
|
||||
#define WGL_ALPHA_SHIFT_ARB 0x201C
|
||||
#define WGL_ACCUM_BITS_ARB 0x201D
|
||||
#define WGL_ACCUM_RED_BITS_ARB 0x201E
|
||||
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
|
||||
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
|
||||
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
|
||||
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||
#define WGL_AUX_BUFFERS_ARB 0x2024
|
||||
|
||||
#define WGL_NO_ACCELERATION_ARB 0x2025
|
||||
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
|
||||
#define WGL_FULL_ACCELERATION_ARB 0x2027
|
||||
|
||||
#define WGL_SWAP_EXCHANGE_ARB 0x2028
|
||||
#define WGL_SWAP_COPY_ARB 0x2029
|
||||
#define WGL_SWAP_UNDEFINED_ARB 0x202A
|
||||
|
||||
#define WGL_TYPE_RGBA_ARB 0x202B
|
||||
#define WGL_TYPE_COLORINDEX_ARB 0x202C
|
||||
|
||||
/* WGL_ARB_create_context */
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
||||
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
|
||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
#define ERROR_INVALID_VERSION_ARB 0x2095
|
||||
#define ERROR_INVALID_PROFILE_ARB 0x2096
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user