750 lines
24 KiB
C++
750 lines
24 KiB
C++
#include "pch.h"
|
|
#include "log.h"
|
|
#include "shader.h"
|
|
#include "shape.h"
|
|
#include "texture.h"
|
|
#include "image.h"
|
|
#include "app.h"
|
|
#include "keymap.h"
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#ifdef TARGET_OS_OSX
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#include <Cocoa/Cocoa.h>
|
|
#include <CoreVideo/CoreVideo.h>
|
|
#include <OpenGL/OpenGL.h>
|
|
@interface View : NSOpenGLView
|
|
{
|
|
CVDisplayLinkRef dl;
|
|
}
|
|
@end @implementation View
|
|
- (instancetype)initWithFrame:(NSRect)frameRect
|
|
{
|
|
NSOpenGLPixelFormatAttribute attrs[] =
|
|
{
|
|
NSOpenGLPFADoubleBuffer,
|
|
NSOpenGLPFADepthSize, 24,
|
|
// Must specify the 3.2 Core Profile to use OpenGL 3.2
|
|
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
|
// Multisample
|
|
NSOpenGLPFAMultisample,
|
|
NSOpenGLPFASamples, 2,
|
|
NSOpenGLPFASampleBuffers, 1,
|
|
0
|
|
};
|
|
NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
|
|
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
|
|
self = [super initWithFrame:frameRect pixelFormat:pf];
|
|
[self setPixelFormat:pf];
|
|
[self setOpenGLContext:context];
|
|
return self;
|
|
}
|
|
- (void)prepareOpenGL
|
|
{
|
|
NSLog(@"prepare");
|
|
|
|
// Synchronize buffer swaps with vertical refresh rate
|
|
GLint swapInt = 1;
|
|
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
|
|
|
// Create a display link capable of being used with all active displays
|
|
CVDisplayLinkCreateWithActiveCGDisplays(&dl);
|
|
|
|
// Set the renderer output callback function
|
|
CVDisplayLinkSetOutputCallback(dl, &MyDisplayLinkCallback, (__bridge void*)self);
|
|
|
|
// Set the display link for the current renderer
|
|
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
|
|
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
|
|
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(dl, cglContext, cglPixelFormat);
|
|
|
|
// Activate the display link
|
|
CVDisplayLinkStart(dl);
|
|
|
|
CGLEnable([self.openGLContext CGLContextObj], kCGLCECrashOnRemovedFunctions);
|
|
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
App::I.init();
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
|
|
// This is the renderer output callback function
|
|
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now,
|
|
const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
|
|
{
|
|
CVReturn result = [(__bridge View*)displayLinkContext getFrameForTime:outputTime];
|
|
return result;
|
|
}
|
|
|
|
- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime
|
|
{
|
|
static double _timeFreq = CVGetHostClockFrequency();
|
|
static double _prevTime = (double)outputTime->hostTime / _timeFreq;
|
|
double hostTime = (double)outputTime->hostTime;
|
|
double now = hostTime / _timeFreq;
|
|
|
|
// this will not update unless 1/30th of a second has passed since the last update
|
|
if ( now < _prevTime + (1.0 / 30.0) )
|
|
{
|
|
// Add your drawing codes here
|
|
[[self openGLContext] makeCurrentContext];
|
|
|
|
// We draw on a secondary thread through the display link
|
|
// When resizing the view, -reshape is called automatically on the main
|
|
// thread. Add a mutex around to avoid the threads accessing the context
|
|
// simultaneously when resizing
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
App::I.clear();
|
|
App::I.update(now - _prevTime);
|
|
|
|
//[[self openGLContext] flushBuffer];
|
|
// returning NO will cause the layer to NOT be redrawn
|
|
|
|
CGLFlushDrawable([[self openGLContext] CGLContextObj]);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
return NO;
|
|
}
|
|
else
|
|
{
|
|
// change whatever you want to change here, as a function of time elapsed
|
|
_prevTime = now;
|
|
// return YES to have your layer redrawn
|
|
return YES;
|
|
}
|
|
|
|
return kCVReturnSuccess;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
// Release the display link
|
|
CVDisplayLinkRelease(dl);
|
|
}
|
|
|
|
- (void)drawRect:(NSRect)dirtyRect
|
|
{
|
|
NSLog(@"drawRect");
|
|
// Add your drawing codes here
|
|
[[self openGLContext] makeCurrentContext];
|
|
|
|
// We draw on a secondary thread through the display link
|
|
// When resizing the view, -reshape is called automatically on the main
|
|
// thread. Add a mutex around to avoid the threads accessing the context
|
|
// simultaneously when resizing
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
App::I.update(0);
|
|
|
|
//[[self openGLContext] flushBuffer];
|
|
// returning NO will cause the layer to NOT be redrawn
|
|
|
|
CGLFlushDrawable([[self openGLContext] CGLContextObj]);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
|
|
- (void)reshape
|
|
{
|
|
[super reshape];
|
|
|
|
// We draw on a secondary thread through the display link. However, when
|
|
// resizing the view, -drawRect is called on the main thread.
|
|
// Add a mutex around to avoid the threads accessing the context
|
|
// simultaneously when resizing.
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
|
|
// Get the view size in Points
|
|
NSRect viewRectPoints = [self bounds];
|
|
|
|
#if SUPPORT_RETINA_RESOLUTION
|
|
|
|
// Rendering at retina resolutions will reduce aliasing, but at the potential
|
|
// cost of framerate and battery life due to the GPU needing to render more
|
|
// pixels.
|
|
|
|
// Any calculations the renderer does which use pixel dimentions, must be
|
|
// in "retina" space. [NSView convertRectToBacking] converts point sizes
|
|
// to pixel sizes. Thus the renderer gets the size in pixels, not points,
|
|
// so that it can set it's viewport and perform and other pixel based
|
|
// calculations appropriately.
|
|
// viewRectPixels will be larger than viewRectPoints for retina displays.
|
|
// viewRectPixels will be the same as viewRectPoints for non-retina displays
|
|
NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints];
|
|
|
|
#else //if !SUPPORT_RETINA_RESOLUTION
|
|
|
|
// App will typically render faster and use less power rendering at
|
|
// non-retina resolutions since the GPU needs to render less pixels.
|
|
// There is the cost of more aliasing, but it will be no-worse than
|
|
// on a Mac without a retina display.
|
|
|
|
// Points:Pixels is always 1:1 when not supporting retina resolutions
|
|
NSRect viewRectPixels = viewRectPoints;
|
|
|
|
#endif // !SUPPORT_RETINA_RESOLUTION
|
|
App::I.resize(viewRectPixels.size.width, viewRectPixels.size.height);
|
|
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)renewGState
|
|
{
|
|
// Called whenever graphics state updated (such as window resize)
|
|
|
|
// OpenGL rendering is not synchronous with other rendering on the OSX.
|
|
// Therefore, call disableScreenUpdatesUntilFlush so the window server
|
|
// doesn't render non-OpenGL content in the window asynchronously from
|
|
// OpenGL content, which could cause flickering. (non-OpenGL content
|
|
// includes the title bar and drawing done by the app with other APIs)
|
|
[[self window] disableScreenUpdatesUntilFlush];
|
|
|
|
[super renewGState];
|
|
}
|
|
- (void)mouseDown:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_down(0, mouseLoc.x, App::I.height - mouseLoc.y - 1, theEvent.pressure);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)rightMouseDown:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_down(1, mouseLoc.x, App::I.height - mouseLoc.y - 1, theEvent.pressure);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)mouseUp:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_up(0, mouseLoc.x, App::I.height - mouseLoc.y - 1);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)rightMouseUp:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_up(1, mouseLoc.x, App::I.height - mouseLoc.y - 1);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)mouseMoved:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_move(mouseLoc.x, App::I.height - mouseLoc.y - 1, theEvent.pressure);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
-(void)mouseDragged:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_move(mouseLoc.x, App::I.height - mouseLoc.y - 1, theEvent.pressure);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)rightMouseDragged:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_move(mouseLoc.x, App::I.height - mouseLoc.y - 1, theEvent.pressure);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)scrollWheel:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
|
App::I.mouse_scroll(mouseLoc.x, App::I.height - mouseLoc.y - 1, [theEvent deltaY]);
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)keyDown:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto keyCode = [theEvent keyCode];
|
|
auto chars = [theEvent characters];
|
|
App::I.key_down(convert_key(keyCode));
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
- (void)keyUp:(NSEvent *)theEvent
|
|
{
|
|
CGLLockContext([[self openGLContext] CGLContextObj]);
|
|
auto keyCode = [theEvent keyCode];
|
|
auto chars = [theEvent characters];
|
|
App::I.key_up(convert_key(keyCode));
|
|
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
|
}
|
|
@end
|
|
|
|
@interface Window : NSWindow
|
|
@end @implementation Window
|
|
- (void)keyDown:(NSEvent *)theEvent
|
|
{
|
|
[[self windowController] keyDown:theEvent];
|
|
}
|
|
@end
|
|
|
|
@interface Controller : NSWindowController<NSWindowDelegate>
|
|
@end @implementation Controller
|
|
- (void)keyDown:(NSEvent *)theEvent
|
|
{
|
|
unichar c = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
|
|
if (c == 27)
|
|
{
|
|
[[NSApplication sharedApplication] terminate:nil];
|
|
}
|
|
}
|
|
- (void)windowDidResize:(NSNotification *)notification
|
|
{
|
|
|
|
}
|
|
@end
|
|
|
|
@interface AppOSX : NSApplication<NSApplicationDelegate>
|
|
{
|
|
Window* window;
|
|
Controller* controller;
|
|
View* view;
|
|
}
|
|
@end @implementation AppOSX
|
|
- (instancetype)init
|
|
{
|
|
self = [super init];
|
|
[self setActivationPolicy:NSApplicationActivationPolicyRegular]; // make it to the front
|
|
[self setDelegate:self];
|
|
return self;
|
|
}
|
|
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
|
{
|
|
App::I.initLog();
|
|
App::I.create();
|
|
NSRect r = NSMakeRect(0, 0, App::I.width, App::I.height);
|
|
|
|
view = [[View alloc] initWithFrame:r];
|
|
|
|
auto style = NSTitledWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask;
|
|
window = [[Window alloc] initWithContentRect:r styleMask:style backing:NSBackingStoreBuffered defer:NO];
|
|
[window setTitle:@"PanoPainter 0.1.2 alpha"];
|
|
[window center];
|
|
[window makeKeyAndOrderFront:controller];
|
|
[window setContentView:view];
|
|
[window setAcceptsMouseMovedEvents:true];
|
|
[window makeFirstResponder:view];
|
|
|
|
controller = [[Controller alloc] initWithWindow:window];
|
|
|
|
auto menubar = [NSMenu new];
|
|
auto appMenuItem = [NSMenuItem new];
|
|
[menubar addItem:appMenuItem];
|
|
[self setMainMenu:menubar];
|
|
|
|
auto appMenu = [NSMenu new];
|
|
auto appName = [[NSProcessInfo processInfo] processName];
|
|
auto quitTitle = [@"Quit " stringByAppendingString:appName];
|
|
auto quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle
|
|
action:@selector(terminate:) keyEquivalent:@"q"];
|
|
[appMenu addItem:quitMenuItem];
|
|
[appMenuItem setSubmenu:appMenu];
|
|
|
|
NSLog(@"app launched");
|
|
}
|
|
@end
|
|
|
|
int main(int argc, const char * argv[])
|
|
{
|
|
AppOSX* app = [AppOSX sharedApplication];
|
|
[app run];
|
|
return 0;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
|
|
#pragma comment (lib, "opengl32.lib")
|
|
#pragma comment (lib, "glew32.lib")
|
|
#pragma comment(lib, "wbemuuid.lib")
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
|
|
HINSTANCE hInst;
|
|
HWND hWnd;
|
|
HDC hDC;
|
|
HGLRC hRC;
|
|
wchar_t* className;
|
|
bool keys[256];
|
|
|
|
#include <WbemCli.h>
|
|
|
|
int read_WMI_info()
|
|
{
|
|
// see: http://win32easy.blogspot.co.uk/2011/03/wmi-in-c-query-everyting-from-your-os.html
|
|
|
|
HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
|
if (FAILED(hRes))
|
|
{
|
|
LOG("Unable to launch COM: %x", hRes);
|
|
return 1;
|
|
}
|
|
|
|
if ((FAILED(hRes = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0))))
|
|
{
|
|
LOG("Unable to initialize security: %x", hRes);
|
|
return 1;
|
|
}
|
|
|
|
IWbemLocator* pLocator = NULL;
|
|
if (FAILED(hRes = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator))))
|
|
{
|
|
LOG("Unable to create a WbemLocator: %x", hRes);
|
|
return 1;
|
|
}
|
|
|
|
IWbemServices* pService = NULL;
|
|
if (FAILED(hRes = pLocator->ConnectServer(L"root\\CIMV2", NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pService)))
|
|
{
|
|
pLocator->Release();
|
|
LOG("Unable to connect to \"CIMV2\": %x", hRes);
|
|
return 1;
|
|
}
|
|
|
|
auto log_field = [](const wchar_t* section, IWbemClassObject* clsObj, const wchar_t* field) {
|
|
VARIANT vRet;
|
|
VariantInit(&vRet);
|
|
if (SUCCEEDED(clsObj->Get(field, 0, &vRet, NULL, NULL)) && vRet.vt == VT_BSTR)
|
|
{
|
|
LOGW(L"%s %s: %s", section, field, vRet.bstrVal);
|
|
VariantClear(&vRet);
|
|
}
|
|
};
|
|
|
|
// GET DEVICE INFO
|
|
{
|
|
IEnumWbemClassObject* pEnumerator = NULL;
|
|
if (FAILED(hRes = pService->ExecQuery(L"WQL", L"SELECT * FROM Win32_ComputerSystem", WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator)))
|
|
{
|
|
pLocator->Release();
|
|
pService->Release();
|
|
LOG("Unable to retrive desktop monitors: %x", hRes);
|
|
return 1;
|
|
}
|
|
|
|
IWbemClassObject* clsObj = NULL;
|
|
int numElems;
|
|
while ((hRes = pEnumerator->Next(WBEM_INFINITE, 1, &clsObj, (ULONG*)&numElems)) != WBEM_S_FALSE)
|
|
{
|
|
if (FAILED(hRes))
|
|
break;
|
|
|
|
log_field(L"Machine", clsObj, L"Name");
|
|
log_field(L"Machine", clsObj, L"Model");
|
|
log_field(L"Machine", clsObj, L"Manufacturer");
|
|
|
|
clsObj->Release();
|
|
}
|
|
pEnumerator->Release();
|
|
}
|
|
|
|
// GET OS INFO
|
|
{
|
|
IEnumWbemClassObject* pEnumerator = NULL;
|
|
if (FAILED(hRes = pService->ExecQuery(L"WQL", L"SELECT * FROM Win32_OperatingSystem", WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator)))
|
|
{
|
|
pLocator->Release();
|
|
pService->Release();
|
|
LOG("Unable to retrive desktop monitors: %x", hRes);
|
|
return 1;
|
|
}
|
|
|
|
IWbemClassObject* clsObj = NULL;
|
|
int numElems;
|
|
while ((hRes = pEnumerator->Next(WBEM_INFINITE, 1, &clsObj, (ULONG*)&numElems)) != WBEM_S_FALSE)
|
|
{
|
|
if (FAILED(hRes))
|
|
break;
|
|
|
|
log_field(L"OS", clsObj, L"Name");
|
|
log_field(L"OS", clsObj, L"Version");
|
|
log_field(L"OS", clsObj, L"Locale");
|
|
log_field(L"OS", clsObj, L"OSProductSuite");
|
|
log_field(L"OS", clsObj, L"Manufacturer");
|
|
log_field(L"OS", clsObj, L"Description");
|
|
|
|
clsObj->Release();
|
|
}
|
|
pEnumerator->Release();
|
|
}
|
|
|
|
pService->Release();
|
|
pLocator->Release();
|
|
CoUninitialize();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
WNDCLASS wc;
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
|
|
App::I.initLog();
|
|
|
|
read_WMI_info();
|
|
|
|
App::I.create();
|
|
RECT clientRect = { 0, 0, (int)App::I.width, (int)App::I.height };
|
|
|
|
// Inizialize data structures to zero
|
|
memset(&wc, 0, sizeof(wc));
|
|
memset(&keys, 0, sizeof(keys));
|
|
memset(&pfd, 0, sizeof(pfd));
|
|
|
|
// Create the main window
|
|
|
|
hInst = GetModuleHandle(NULL);
|
|
className = L"EngineMain";
|
|
|
|
wc.hInstance = hInst;
|
|
wc.lpfnWndProc = (WNDPROC)WndProc;
|
|
wc.lpszClassName = className;
|
|
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
RegisterClass(&wc);
|
|
|
|
AdjustWindowRect(&clientRect, WS_OVERLAPPEDWINDOW, false);
|
|
hWnd = CreateWindow(wc.lpszClassName, L"New Engine", WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, clientRect.right - clientRect.left,
|
|
clientRect.bottom - clientRect.top, 0, 0, hInst, 0);
|
|
|
|
// Setup GL Rendering Context
|
|
pfd.nSize = sizeof(pfd);
|
|
pfd.nVersion = 1;
|
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
|
pfd.cColorBits = 32;
|
|
pfd.cDepthBits = 16;
|
|
pfd.iLayerType = PFD_MAIN_PLANE;
|
|
|
|
hDC = GetDC(hWnd);
|
|
int pxfmt = ChoosePixelFormat(hDC, &pfd);
|
|
SetPixelFormat(hDC, pxfmt, &pfd);
|
|
hRC = wglCreateContext(hDC); // Create OpenGL 2.1 or less
|
|
wglMakeCurrent(hDC, hRC);
|
|
|
|
// Initialize extensions
|
|
if (glewInit() != GLEW_OK)
|
|
return 0;
|
|
|
|
LOG("GL version: %s", glGetString(GL_VERSION));
|
|
LOG("GL vendor: %s", glGetString(GL_VENDOR));
|
|
LOG("GL renderer: %s", glGetString(GL_RENDERER));
|
|
|
|
// If supported create a 3.1 context
|
|
if (wglewIsSupported("WGL_ARB_create_context"))
|
|
{
|
|
int contex_attribs[] =
|
|
{
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
|
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
|
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
0
|
|
};
|
|
int pixel_attribs[] =
|
|
{
|
|
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
|
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
|
|
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
|
|
WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
|
|
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
|
|
WGL_COLOR_BITS_ARB, 32,
|
|
WGL_DEPTH_BITS_ARB, 24,
|
|
WGL_STENCIL_BITS_ARB, 8,
|
|
// WGL_SAMPLE_BUFFERS_ARB, 1, // Number of buffers (must be 1 at time of writing)
|
|
// WGL_SAMPLES_ARB, 4, // Number of samples
|
|
0
|
|
};
|
|
UINT numFormat;
|
|
|
|
wglMakeCurrent(NULL, NULL);
|
|
wglDeleteContext(hRC);
|
|
DestroyWindow(hWnd);
|
|
|
|
hWnd = CreateWindow(wc.lpszClassName, L"PanoPainter 0.1.2 alpha - OpenGL 3.1", WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, clientRect.right - clientRect.left,
|
|
clientRect.bottom - clientRect.top, 0, 0, hInst, 0);
|
|
|
|
hDC = GetDC(hWnd);
|
|
wglChoosePixelFormatARB(hDC, pixel_attribs, nullptr, 1, &pxfmt, &numFormat);
|
|
SetPixelFormat(hDC, pxfmt, &pfd);
|
|
hRC = wglCreateContextAttribsARB(hDC, NULL, contex_attribs);
|
|
wglMakeCurrent(hDC, hRC);
|
|
}
|
|
else
|
|
{
|
|
// If not supported, go fuck yourself we are not gonna use that shit
|
|
return -1; // A negative number because you are a negative one
|
|
}
|
|
|
|
App::I.init();
|
|
|
|
ShowWindow(hWnd, SW_NORMAL);
|
|
|
|
MSG msg;
|
|
bool running = true;
|
|
unsigned long t0 = GetTickCount();
|
|
unsigned long t1;
|
|
while (running)
|
|
{
|
|
// If there any message in the queue process it
|
|
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
|
{
|
|
running = !(msg.message == WM_QUIT/* || gl.keys[VK_ESCAPE]*/);
|
|
DispatchMessage(&msg);
|
|
TranslateMessage(&msg);
|
|
}
|
|
else // Otherwise render next frame
|
|
{
|
|
t1 = GetTickCount();
|
|
float dt = (float)(t1 - t0) / 1000.0f;
|
|
if (dt > 1.0f / 60.0f)
|
|
{
|
|
App::I.clear();
|
|
App::I.update((float)(t1 - t0) / 1000.0f);
|
|
t0 = t1;
|
|
SwapBuffers(hDC);
|
|
}
|
|
else
|
|
{
|
|
Sleep((DWORD)(1.0f / 60.0f * 1000.f));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean up
|
|
DestroyWindow(hWnd);
|
|
UnregisterClass(className, hInst);
|
|
}
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
{
|
|
switch (msg)
|
|
{
|
|
case WM_CLOSE:
|
|
PostQuitMessage(0);
|
|
break;
|
|
case WM_SIZE:
|
|
App::I.resize((float)LOWORD(lp), (float)HIWORD(lp));
|
|
App::I.clear();
|
|
App::I.update(0.f);
|
|
SwapBuffers(hDC);
|
|
break;
|
|
case WM_KEYDOWN:
|
|
keys[wp] = true;
|
|
App::I.key_down(convert_key((int)wp));
|
|
break;
|
|
case WM_KEYUP:
|
|
keys[wp] = false;
|
|
App::I.key_up(convert_key((int)wp));
|
|
break;
|
|
case WM_CHAR:
|
|
App::I.key_char((int)wp);
|
|
break;
|
|
case WM_MOUSEMOVE:
|
|
App::I.mouse_move((float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp));
|
|
break;
|
|
case WM_LBUTTONDOWN:
|
|
App::I.mouse_down(0, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp));
|
|
SetCapture(hWnd);
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
App::I.mouse_up(0, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp));
|
|
ReleaseCapture();
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
App::I.mouse_down(1, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp));
|
|
SetCapture(hWnd);
|
|
break;
|
|
case WM_RBUTTONUP:
|
|
App::I.mouse_up(1, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp));
|
|
ReleaseCapture();
|
|
break;
|
|
case WM_MOUSEWHEEL:
|
|
{
|
|
POINT pt;
|
|
pt.x = GET_X_LPARAM(lp);
|
|
pt.y = GET_Y_LPARAM(lp);
|
|
ScreenToClient(hWnd, &pt);
|
|
App::I.mouse_scroll((float)pt.x, (float)pt.y,
|
|
(float)GET_WHEEL_DELTA_WPARAM(wp) / (float)WHEEL_DELTA);
|
|
break;
|
|
}
|
|
case WM_POINTERUPDATE:
|
|
{
|
|
POINTER_TOUCH_INFO touchInfo;
|
|
POINTER_PEN_INFO penInfo;
|
|
POINTER_INFO pointerInfo;
|
|
UINT32 pointerId = GET_POINTERID_WPARAM(wp);
|
|
POINTER_INPUT_TYPE pointerType = PT_POINTER;
|
|
|
|
// Retrieve common pointer information
|
|
if (!GetPointerInfo(pointerId, &pointerInfo))
|
|
{
|
|
// failure, call GetLastError()
|
|
}
|
|
else
|
|
{
|
|
// success, process pointerInfo
|
|
if (!GetPointerType(pointerId, &pointerType))
|
|
{
|
|
// failure, call GetLastError()
|
|
// set PT_POINTER to fall to default case below
|
|
pointerType = PT_POINTER;
|
|
}
|
|
switch (pointerType)
|
|
{
|
|
case PT_TOUCH:
|
|
// Retrieve touch information
|
|
if (!GetPointerTouchInfo(pointerId, &touchInfo))
|
|
{
|
|
// failure, call GetLastError()
|
|
}
|
|
else
|
|
{
|
|
// success, process touchInfo
|
|
// mark as handled to skip call to DefWindowProc
|
|
//fHandled = TRUE;
|
|
}
|
|
break;
|
|
case PT_PEN:
|
|
// Retrieve pen information
|
|
if (!GetPointerPenInfo(pointerId, &penInfo))
|
|
{
|
|
// failure, call GetLastError()
|
|
}
|
|
else
|
|
{
|
|
// success, process penInfo
|
|
// mark as handled to skip call to DefWindowProc
|
|
//fHandled = TRUE;
|
|
//penInfo.pressure
|
|
}
|
|
break;
|
|
default:
|
|
if (!GetPointerInfo(pointerId, &pointerInfo))
|
|
{
|
|
// failure.
|
|
}
|
|
else
|
|
{
|
|
// success, proceed with pointerInfo.
|
|
//fHandled = HandleGenericPointerInfo(&pointerInfo);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
return DefWindowProc(hWnd, msg, wp, lp);
|
|
}
|
|
|
|
#endif
|