Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macos2 #9

Merged
merged 3 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/windy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export common, vmath
when defined(windows):
import windy/platforms/win32/platform
elif defined(macosx):
import windy/platforms/macos/platform
import windy/platforms/macos2/platform
elif defined(linux):
import windy/platforms/x11/platform

Expand Down
235 changes: 235 additions & 0 deletions src/windy/platforms/macos2/macos.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#import <Cocoa/Cocoa.h>

NSInteger const decoratedWindowMask = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask;
NSInteger const undecoratedWindowMask = NSBorderlessWindowMask | NSMiniaturizableWindowMask;

static void postEmptyEvent(void) {
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:0
data1:0
data2:0];
[NSApp postEvent:event atStart:YES];
}

static void createMenuBar(void) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

id menubar = [NSMenu new];
id appMenuItem = [NSMenuItem new];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];

id appMenu = [NSMenu new];
NSString* appName = [[NSProcessInfo processInfo] processName];
id quitTitle = [@"Quit " stringByAppendingString:appName];
id quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle
action:@selector(terminate:) keyEquivalent:@"q"];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
}

static int pickOpenGLProfile(int majorVersion) {
if (majorVersion == 4) {
return NSOpenGLProfileVersion4_1Core;
}
if (majorVersion == 3) {
return NSOpenGLProfileVersion3_2Core;
}
return NSOpenGLProfileVersionLegacy;
}

@interface WindyApplicationDelegate : NSObject <NSApplicationDelegate>
@end

@implementation WindyApplicationDelegate

- (void)applicationWillFinishLaunching:(NSNotification*)notification {
createMenuBar();
}

- (void)applicationDidFinishLaunching:(NSNotification*)notification {
// Post an empty event then stop the NSApp run from innerInit()
postEmptyEvent();
[NSApp stop:nil];
}

@end

@interface WindyWindow : NSWindow
@end

@implementation WindyWindow
@end

@interface WindyContentView : NSOpenGLView
@end

@implementation WindyContentView

- (id) initWithFrameAndConfig:(NSRect)frame
vsync:(bool)vsync
openglMajorVersion:(int)openglMajorVersion
openglMinorVersion:(int)openglMinorVersion
msaa:(int)msaa
depthBits:(int)depthBits
stencilBits:(int)stencilBits {
NSOpenGLPixelFormatAttribute attribs[] =
{
NSOpenGLPFAMultisample,
NSOpenGLPFASampleBuffers, msaa > 0 ? 1 : 0,
NSOpenGLPFASamples, msaa,
NSOpenGLPFAAccelerated,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAColorSize, 32,
NSOpenGLPFAAlphaSize, 8,
NSOpenGLPFADepthSize, depthBits,
NSOpenGLPFAStencilSize, stencilBits,
NSOpenGLPFAOpenGLProfile, pickOpenGLProfile(openglMajorVersion),
0
};

NSOpenGLPixelFormat* pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];

self = [super initWithFrame:frame pixelFormat:pf];

[[self openGLContext] makeCurrentContext];

GLint swapInterval = vsync ? 1 : 0;
[[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];

return self;
}

@end

WindyApplicationDelegate* appDelegate;

void innerInit() {
[NSApplication sharedApplication];

appDelegate = [[WindyApplicationDelegate alloc] init];
[NSApp setDelegate:appDelegate];

[NSApp run]; // We will break out of this in applicationDidFinishLaunching
}

void innerNewPlatformWindow(
char* title,
int width,
int height,
bool vsync,
int openglMajorVersion,
int openglMinorVersion,
int msaa,
int depthBits,
int stencilBits,
WindyWindow** windowRet
) {
NSRect contentRect = NSMakeRect(0, 0, width, height);

WindyWindow* window = [[WindyWindow alloc] initWithContentRect:contentRect
styleMask:decoratedWindowMask
backing:NSBackingStoreBuffered
defer:NO];

WindyContentView* view = [[WindyContentView alloc] initWithFrameAndConfig:contentRect
vsync:vsync
openglMajorVersion:openglMajorVersion
openglMinorVersion:openglMinorVersion
msaa:msaa
depthBits:depthBits
stencilBits:stencilBits];

[window setContentView:view];
[window setTitle:[NSString stringWithUTF8String:title]];

*windowRet = window;
}

void innerMakeContextCurrent(WindyWindow* window) {
[[[window contentView] openGLContext] makeCurrentContext];
}

void innerSwapBuffers(WindyWindow* window) {
[[[window contentView] openGLContext] flushBuffer];
}

void innerPollEvents() {
while (true) {
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event == nil) {
break;
}

[NSApp sendEvent:event];
}
}

bool innerGetVisible(WindyWindow* window) {
return window.isVisible;
}

bool innerGetDecorated(WindyWindow* window) {
return (window.styleMask & NSTitledWindowMask) != 0;
}

bool innerGetResizable(WindyWindow* window) {
return (window.styleMask & NSResizableWindowMask) != 0;
}

void innerGetSize(WindyWindow* window, int* width, int* height) {
NSRect contentRect = [[window contentView] frame];
*width = contentRect.size.width;
*height = contentRect.size.height;
}

void innerGetPos(WindyWindow* window, int* x, int* y) {
NSRect contentRect = [window contentRectForFrameRect:[window frame]];
*x = contentRect.origin.x;
*y = contentRect.origin.y;
}

void innerSetVisible(WindyWindow* window, bool visible) {
if (visible) {
[window orderFront:nil];
} else {
[window orderOut:nil];
}
}

void innerSetDecorated(WindyWindow* window, bool decorated) {
window.styleMask = decorated ? decoratedWindowMask : undecoratedWindowMask;
}

void innerSetResizable(WindyWindow* window, bool resizable) {
if (!innerGetDecorated(window)) {
return;
}

if (resizable) {
window.styleMask |= NSResizableWindowMask;
} else {
window.styleMask &= ~NSResizableWindowMask;
}
}

void innerSetSize(WindyWindow* window, int width, int height) {
NSRect contentRect = [window contentRectForFrameRect:[window frame]];
contentRect.origin.y += contentRect.size.height - height;
contentRect.size = NSMakeSize(width, height);
[window setFrame:[window frameRectForContentRect:contentRect]
display:YES];
}

void innerSetPos(WindyWindow* window, int x, int y) {
NSRect rect = NSMakeRect(x, y, 0, 0);
[window setFrameOrigin:rect.origin];
}
120 changes: 120 additions & 0 deletions src/windy/platforms/macos2/platform.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{.
passL: "-framework Cocoa",
compile: "macos.m",
.}

import ../../common, vmath

type PlatformWindow* = ref object
windowPtr: pointer

proc innerInit() {.importc.}

proc innerNewPlatformWindow(
title: cstring,
width: int32,
height: int32,
vsync: bool,
openglMajorVersion: int32,
openglMinorVersion: int32,
msaa: int32,
depthBits: int32,
stencilBits: int32,
windowRet: ptr pointer
) {.importc.}

proc innerMakeContextCurrent(windowPtr: pointer) {.importc.}

proc innerSwapBuffers(windowPtr: pointer) {.importc.}

proc innerPollEvents() {.importc.}

proc innerGetVisible(windowPtr: pointer): bool {.importc.}

proc innerSetVisible(windowPtr: pointer, visible: bool) {.importc.}

proc innerGetDecorated(windowPtr: pointer): bool {.importc.}

proc innerSetDecorated(windowPtr: pointer, decorated: bool) {.importc.}

proc innerGetResizable(windowPtr: pointer): bool {.importc.}

proc innerSetResizable(windowPtr: pointer, resizable: bool) {.importc.}

proc innerGetSize(windowPtr: pointer, width, height: ptr int32) {.importc.}

proc innerSetSize(windowPtr: pointer, width, height: int32) {.importc.}

proc innerGetPos(windowPtr: pointer, x, y: ptr int32) {.importc.}

proc innerSetPos(windowPtr: pointer, x, y: int32) {.importc.}

proc platformInit*() =
innerInit()

proc newPlatformWindow*(
title: string,
size: IVec2,
vsync: bool,
openglMajorVersion: int,
openglMinorVersion: int,
msaa: MSAA,
depthBits: int,
stencilBits: int
): PlatformWindow =
result = PlatformWindow()
innerNewPlatformWindow(
title,
size.x,
size.y,
vsync,
openglMajorVersion.int32,
openglMinorVersion.int32,
msaa.int32,
depthBits.int32,
stencilBits.int32,
result.windowPtr.addr
)

proc makeContextCurrent*(window: PlatformWindow) =
innerMakeContextCurrent(window.windowPtr)

proc swapBuffers*(window: PlatformWindow) =
innerSwapBuffers(window.windowPtr)

proc platformPollEvents*() =
innerPollEvents()

proc visible*(window: PlatformWindow): bool =
innerGetVisible(window.windowPtr)

proc `visible=`*(window: PlatformWindow, visible: bool) =
innerSetVisible(window.windowPtr, visible)

proc decorated*(window: PlatformWindow): bool =
innerGetDecorated(window.windowPtr)

proc `decorated=`*(window: PlatformWindow, decorated: bool) =
innerSetDecorated(window.windowPtr, decorated)

proc resizable*(window: PlatformWindow): bool =
innerGetResizable(window.windowPtr)

proc `resizable=`*(window: PlatformWindow, resizable: bool) =
innerSetResizable(window.windowPtr, resizable)

proc size*(window: PlatformWindow): IVec2 =
var width, height: int32
innerGetSize(window.windowPtr, width.addr, height.addr)
ivec2(width, height)

proc `size=`*(window: PlatformWindow, size: IVec2) =
innerSetSize(window.windowPtr, size.x, size.y)

proc pos*(window: PlatformWindow): IVec2 =
var x, y: int32
innerGetPos(window.windowPtr, x.addr, y.addr)
ivec2(x, y)

proc `pos=`*(window: PlatformWindow, pos: Ivec2) =
innerSetPos(window.windowPtr, pos.x, pos.y)
Loading