#include "pch.h" #include "shader.hpp" #include "shape.hpp" #include "texture.hpp" #include "image.hpp" #include "app.hpp" #ifdef __APPLE__ #include #include #include #include @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 { 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