Skip to content

Commit

Permalink
Merge pull request #9 from guzba/master
Browse files Browse the repository at this point in the history
macos2
  • Loading branch information
treeform authored Oct 18, 2021
2 parents be2df9e + 708c5b9 commit fb09cb0
Show file tree
Hide file tree
Showing 5 changed files with 390 additions and 29 deletions.
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

0 comments on commit fb09cb0

Please sign in to comment.