Files
panopainter/engine/main.cpp

373 lines
10 KiB
C++

#include "pch.h"
#include "shader.hpp"
#include "shape.hpp"
#include "texture.hpp"
#include "image.hpp"
#include "app.hpp"
#ifdef __APPLE__
#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);
App::I.init();
}
// 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];
App::I.update(now - _prevTime);
[[self openGLContext] flushBuffer];
// returning NO will cause the layer to NOT be redrawn
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");
}
@end
@interface Window : NSWindow
@end @implementation Window
- (void)keyDown:(NSEvent *)theEvent
{
[[self windowController] keyDown:theEvent];
}
@end
@interface Controller : NSWindowController
@end @implementation Controller
- (void)keyDown:(NSEvent *)theEvent
{
unichar c = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
if (c == 27)
{
[[NSApplication sharedApplication] terminate:nil];
}
}
@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
{
auto& app = App::I;
app.create();
NSRect r = NSMakeRect(0, 0, app.width, app.height);
view = [[View alloc] initWithFrame:r];
window = [[Window alloc] initWithContentRect:r
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[window setTitle:@"hello engine - ui shapes"];
[window center];
[window makeKeyAndOrderFront:controller];
[window setContentView: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
#ifdef _WIN32
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glew32.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];
int main()
{
WNDCLASS wc;
PIXELFORMATDESCRIPTOR pfd;
App::I.create();
RECT clientRect = { 0, 0, App::I.width, 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;
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;
printf("GL version: %s\n", glGetString(GL_VERSION));
printf("GL vendor: %s\n", glGetString(GL_VENDOR));
printf("GL renderer: %s\n", 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, 0,
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"New Engine", 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.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_KEYDOWN:
keys[wp] = true;
break;
case WM_KEYUP:
keys[wp] = false;
break;
case WM_MOUSEMOVE:
//current->pointerMove(LOWORD(lp), HIWORD(lp));
break;
case WM_LBUTTONDOWN:
//current->pointerDown(LOWORD(lp), HIWORD(lp));
break;
case WM_LBUTTONUP:
//current->pointerUp(LOWORD(lp), HIWORD(lp));
break;
}
return DefWindowProc(hWnd, msg, wp, lp);
}
#endif