Began building out the osx platform layer
This commit is contained in:
parent
b843937295
commit
f874ba5289
|
@ -0,0 +1,7 @@
|
||||||
|
pushd build
|
||||||
|
clang++ ../osx/gs_osx.mm \
|
||||||
|
-g \
|
||||||
|
-Wno-c11-extensions -Wno-unused-variable -Wno-unused-function \
|
||||||
|
-framework Cocoa -framework OpenGL \
|
||||||
|
-o osx_foldhaus.out
|
||||||
|
popd
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <objc/message.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
typedef struct AppDel {
|
||||||
|
Class isa;
|
||||||
|
id window;
|
||||||
|
} AppDelegate;
|
||||||
|
|
||||||
|
BOOL AppDel_didFinishLaunching(AppDelegate* self, SEL _command, id Notification)
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ArgCount, char** Args)
|
||||||
|
{
|
||||||
|
Class NSApplicationClass = (Class)objc_getClass("NSApplication");
|
||||||
|
Class AppDelegateClass = objc_allocateClassPair(NSApplicationClass, "AppDelegate", 0);
|
||||||
|
|
||||||
|
SEL MethodSelector = sel_getUid("applicationDidFinishLaunching:");
|
||||||
|
// NOTE(Peter): i = int, @ = object, : = method selector (SEL)
|
||||||
|
char MethodSignature[] = "i@:@";
|
||||||
|
class_addMethod(AppDelegateClass, MethodSelector, (IMP)AppDel_didFinishLaunching, "i@:@");
|
||||||
|
objc_registerClassPair(AppDelegateClass);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
#include "gs_osx_memory.mm"
|
||||||
|
#include "gs_osx_window.mm"
|
||||||
|
#include "gs_osx_fileio.mm"
|
||||||
|
#include "gs_osx_lib.mm"
|
||||||
|
#include "gs_osx_opengl.mm"
|
||||||
|
#include "gs_osx_time.mm"
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsosx_ProcessWindowEvents(NSApplication* App, NSWindow* Window)
|
||||||
|
{
|
||||||
|
// Process Events
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
NSEvent* Event = [App nextEventMatchingMask: NSEventMaskAny untilDate: [NSDate distantPast] inMode: NSDefaultRunLoopMode dequeue: YES];
|
||||||
|
if (!Event) { break; }
|
||||||
|
|
||||||
|
switch([Event type])
|
||||||
|
{
|
||||||
|
case NSEventTypeKeyUp:
|
||||||
|
case NSEventTypeKeyDown:
|
||||||
|
{
|
||||||
|
// TODO: Handle Key Presses
|
||||||
|
}break;
|
||||||
|
|
||||||
|
// TODO: Mouse Input
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
[App sendEvent: Event];
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ArgCount, char** Args)
|
||||||
|
{
|
||||||
|
NSApplication* Application = [NSApplication sharedApplication];
|
||||||
|
[Application setActivationPolicy: NSApplicationActivationPolicyRegular];
|
||||||
|
|
||||||
|
gsosx_ApplicationDelegate* Delegate = [[gsosx_ApplicationDelegate alloc] init];
|
||||||
|
[Application setDelegate: Delegate];
|
||||||
|
|
||||||
|
int WindowWidth = 1024;
|
||||||
|
int WindowHeight = 768;
|
||||||
|
id AppName = @"Lumenarium";
|
||||||
|
NSWindow* Window = gsosx_CreateWindow(Application, WindowWidth, WindowHeight, AppName);
|
||||||
|
|
||||||
|
// A really cryptic way of asking the window to open
|
||||||
|
[Window makeKeyAndOrderFront: Application];
|
||||||
|
|
||||||
|
NSOpenGLContext* OpenGLContext = gsoo_CreateOpenGLContext(Window, WindowWidth, WindowHeight, true);
|
||||||
|
|
||||||
|
gsosx_time_info TimeInfo = gsosx_InitTime();
|
||||||
|
double TargetSecondsPerFrame = 1.0 / 60;
|
||||||
|
uint64_t LastFrameEnd = gsosx_GetTime(TimeInfo);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
gsosx_ProcessWindowEvents(Application, Window);
|
||||||
|
|
||||||
|
glClearColor(1, 0, 1, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
gsoo_SwapBuffers(OpenGLContext);
|
||||||
|
|
||||||
|
uint64_t ThisFrameEnd = gsosx_GetTime(TimeInfo);
|
||||||
|
double FrameSeconds = gsosx_GetSecondsElapsed(LastFrameEnd, ThisFrameEnd, TimeInfo);
|
||||||
|
double SleepSeconds = TargetSecondsPerFrame - FrameSeconds;
|
||||||
|
if (SleepSeconds > 0)
|
||||||
|
{
|
||||||
|
gsosx_Sleep(SleepSeconds, TimeInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
gsosx_GetLastFileWriteTime(char* Path)
|
||||||
|
{
|
||||||
|
int32_t Result = 0;
|
||||||
|
struct stat FileStat = {0};
|
||||||
|
if (stat(Path, &FileStat) == 0)
|
||||||
|
{
|
||||||
|
Result = FileStat.st_mtimespec.tv_sec;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Asserts
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
gsosx_GetFilesize(char* Path)
|
||||||
|
{
|
||||||
|
uint32_t Result = 0;
|
||||||
|
|
||||||
|
int FileHandle = open(Path, O_RDONLY);
|
||||||
|
struct stat FileStat = {0};
|
||||||
|
fstat(FileHandle, &FileStat);
|
||||||
|
close(FileHandle);
|
||||||
|
|
||||||
|
Result = (uint32_t)FileStat.st_size;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gsosx_LoadFileIntoMemory(char* Path, uint32_t FileSize, uint8_t* FileMemory)
|
||||||
|
{
|
||||||
|
bool Result = false;
|
||||||
|
int FileHandle = open(Path, O_RDONLY);
|
||||||
|
|
||||||
|
struct stat FileStat = {0};
|
||||||
|
fstat(FileHandle, &FileStat);
|
||||||
|
if (FileStat.st_size <= FileSize)
|
||||||
|
{
|
||||||
|
read(FileHandle, FileMemory, FileSize);
|
||||||
|
Result = true;
|
||||||
|
}
|
||||||
|
close(FileHandle);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gsosx_WriteEntireFile(char* Path, uint32_t FileSize, uint8_t* FileMemory)
|
||||||
|
{
|
||||||
|
bool Result = false;
|
||||||
|
int FileHandle = open(Path, O_WRONLY | O_CREAT, 0777);
|
||||||
|
ssize_t SizeWritten = write(FileHandle, FileMemory, FileSize);
|
||||||
|
if (SizeWritten == FileSize)
|
||||||
|
{
|
||||||
|
Result = true;
|
||||||
|
}
|
||||||
|
close(FileHandle);
|
||||||
|
return Result;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
static void*
|
||||||
|
gsosx_LoadDLL(char* Path)
|
||||||
|
{
|
||||||
|
void* LibHandle = 0;
|
||||||
|
|
||||||
|
LibHandle = dlopen(Path, RTLD_LAZY);
|
||||||
|
if (LibHandle)
|
||||||
|
{
|
||||||
|
dlerror(); // Clear Last Error
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LibHandle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LibHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define gsosx_GetProcAddress(libHandle, type, name) (type*)dlsym((libHandle), name)
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsosx_UnloadDLL(void* LibHandle)
|
||||||
|
{
|
||||||
|
if (LibHandle)
|
||||||
|
{
|
||||||
|
dlclose(LibHandle);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static uint8_t*
|
||||||
|
gsosx_Alloc(size_t Size)
|
||||||
|
{
|
||||||
|
uint8_t* Result = 0;
|
||||||
|
char* StartAddress = (char*)0;
|
||||||
|
int Prot = PROT_READ | PROT_WRITE;
|
||||||
|
int Flags = MAP_PRIVATE | MAP_ANON;
|
||||||
|
Result = (uint8_t*)mmap(StartAddress, Size, Prot, Flags, -1, 0);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsosx_Free(uint8_t* Base, uint32_t Size)
|
||||||
|
{
|
||||||
|
munmap((void*)Base, (size_t)Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t*
|
||||||
|
gsosx_Realloc(uint8_t* Base, uint32_t OldSize, uint32_t NewSize)
|
||||||
|
{
|
||||||
|
uint8_t* Result = gsosx_Alloc(NewSize);
|
||||||
|
for (int32_t i = 0; i < OldSize; i++)
|
||||||
|
{
|
||||||
|
Result[i] = Base[i];
|
||||||
|
}
|
||||||
|
gsosx_Free(Base, OldSize );
|
||||||
|
return Result;
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include <OpenGL/gl.h>
|
||||||
|
|
||||||
|
struct gsoo_opengl_state
|
||||||
|
{
|
||||||
|
NSOpenGLContext* Context;
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface gsoo_OpenGLView: NSOpenGLView @end
|
||||||
|
@implementation gsoo_OpenGLView : NSOpenGLView
|
||||||
|
- (void)
|
||||||
|
reshape
|
||||||
|
{
|
||||||
|
// TODO: framebufferWidth and Height were globals in the code I was pulling from
|
||||||
|
// Need some way to get the new window height in here.
|
||||||
|
CGRect FrameRect = self.frame;
|
||||||
|
glViewport(0, 0, FrameRect.size.width, FrameRect.size.height);
|
||||||
|
//glViewport(0, 0, framebufferWidth, framebufferHeight);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static NSOpenGLContext*
|
||||||
|
gsoo_CreateOpenGLContext(NSWindow* Window, uint32_t Width, uint32_t Height, int32_t EnableVSync)
|
||||||
|
{
|
||||||
|
NSOpenGLContext* Result = 0;
|
||||||
|
NSOpenGLPixelFormatAttribute PixelFormatAttributes[] = {
|
||||||
|
NSOpenGLPFAClosestPolicy,
|
||||||
|
NSOpenGLPFADoubleBuffer,
|
||||||
|
NSOpenGLPFASampleBuffers,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
NSOpenGLPixelFormat* PixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes: PixelFormatAttributes];
|
||||||
|
Result = [[NSOpenGLContext alloc] initWithFormat: PixelFormat shareContext: 0];
|
||||||
|
|
||||||
|
if (!Result)
|
||||||
|
{
|
||||||
|
// TODO: Assert/Handle
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Result makeCurrentContext];
|
||||||
|
GLint VSync = EnableVSync;
|
||||||
|
[Result setValues: &VSync forParameter: NSOpenGLCPSwapInterval];
|
||||||
|
|
||||||
|
// Set Backbuffer Resolution
|
||||||
|
GLint BackbufferDimensions[] = { Width, Height };
|
||||||
|
CGLSetParameter(Result.CGLContextObj, kCGLCPSurfaceBackingSize, BackbufferDimensions);
|
||||||
|
CGLEnable(Result.CGLContextObj, kCGLCESurfaceBackingSize);
|
||||||
|
|
||||||
|
//
|
||||||
|
gsoo_OpenGLView* View = [[gsoo_OpenGLView alloc] init];
|
||||||
|
[Window setContentView: View];
|
||||||
|
[View setOpenGLContext: Result];
|
||||||
|
[View setPixelFormat: PixelFormat];
|
||||||
|
[Result setView: View];
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsoo_SwapBuffers(NSOpenGLContext* OpenGLContext)
|
||||||
|
{
|
||||||
|
[OpenGLContext flushBuffer];
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
|
||||||
|
static const uint64_t NANOS_PER_USEC = 1000ULL;
|
||||||
|
static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC;
|
||||||
|
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC;
|
||||||
|
|
||||||
|
struct gsosx_time_info
|
||||||
|
{
|
||||||
|
uint64_t StartTimeAbsolute;
|
||||||
|
mach_timebase_info_data_t MachTimeInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gsosx_time_info
|
||||||
|
gsosx_InitTime()
|
||||||
|
{
|
||||||
|
gsosx_time_info Result = {0};
|
||||||
|
Result.StartTimeAbsolute = mach_absolute_time();
|
||||||
|
mach_timebase_info(&Result.MachTimeInfo);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
gsosx_GetTime(gsosx_time_info TimeInfo)
|
||||||
|
{
|
||||||
|
uint64_t Result = mach_absolute_time() - TimeInfo.StartTimeAbsolute;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
gsosx_GetSecondsElapsed(uint64_t Start, uint64_t End, gsosx_time_info TimeInfo)
|
||||||
|
{
|
||||||
|
double Result = 0;
|
||||||
|
double Elapsed = (double)(End - Start);
|
||||||
|
Result = Elapsed * (double)(TimeInfo.MachTimeInfo.numer) / (double)NANOS_PER_SEC / (double)TimeInfo.MachTimeInfo.denom;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gsosx_Sleep(double Seconds, gsosx_time_info TimeInfo)
|
||||||
|
{
|
||||||
|
// NOTE(Peter): This isn't entirely precise, and can vary by up to 500 microseconds. We could implement a sleep combined witha busy wait
|
||||||
|
// to get more precise sleeping. Do this if necessary
|
||||||
|
uint64_t WaitTimeAbs = Seconds / (double)TimeInfo.MachTimeInfo.numer * (double)NANOS_PER_SEC * (double)TimeInfo.MachTimeInfo.denom;
|
||||||
|
uint64_t NowAbs = mach_absolute_time();
|
||||||
|
mach_wait_until(NowAbs + WaitTimeAbs);
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
@interface gsosx_ApplicationDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> @end
|
||||||
|
|
||||||
|
@implementation gsosx_ApplicationDelegate : NSObject
|
||||||
|
- (void)
|
||||||
|
applicationDidFinishLaunching: (NSNotification *)notification
|
||||||
|
{
|
||||||
|
[NSApp stop: nil];
|
||||||
|
NSAutoreleasePool* Pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
[Pool drain];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSApplicationTerminateReply)
|
||||||
|
applicationShouldTerminate: (NSApplication*) sender
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)
|
||||||
|
dealloc
|
||||||
|
{
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface gsosx_WindowDelegate: NSObject<NSWindowDelegate> @end
|
||||||
|
@implementation gsosx_WindowDelegate : NSObject
|
||||||
|
- (BOOL)
|
||||||
|
windowShouldClose: (id)sender
|
||||||
|
{
|
||||||
|
// TODO(Peter): Stop Application Running?
|
||||||
|
NSLog(@"Close button pressed");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)
|
||||||
|
windowDidBecomeKey: (NSNotification*)notification
|
||||||
|
{
|
||||||
|
// TODO: ???
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)
|
||||||
|
windowDisResignKey: (NSNotification*)notification
|
||||||
|
{
|
||||||
|
// TODO: ???
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
static NSWindow*
|
||||||
|
gsosx_CreateWindow(NSApplication* App, int Width, int Height, id Title)
|
||||||
|
{
|
||||||
|
int WindowStyleMask = NSWindowStyleMaskClosable;
|
||||||
|
NSRect WindowRect = NSMakeRect(0, 0, Width, Height);
|
||||||
|
|
||||||
|
NSWindow* Window = [[NSWindow alloc] initWithContentRect: WindowRect styleMask: WindowStyleMask backing: NSBackingStoreBuffered defer: YES];
|
||||||
|
Window.styleMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
|
||||||
|
|
||||||
|
gsosx_WindowDelegate* WindowDelegate = [[gsosx_WindowDelegate alloc] init];
|
||||||
|
|
||||||
|
[Window setOpaque: YES];
|
||||||
|
[Window setDelegate: WindowDelegate];
|
||||||
|
[Window setTitle: Title];
|
||||||
|
|
||||||
|
NSMenu* MenuBar = [NSMenu alloc];
|
||||||
|
NSMenuItem* AppMenuItem = [NSMenuItem alloc];
|
||||||
|
[MenuBar addItem: AppMenuItem];
|
||||||
|
[App setMainMenu: MenuBar];
|
||||||
|
|
||||||
|
NSMenu* AppMenu = [NSMenu alloc];
|
||||||
|
id QuitTitle = [@"Quit " stringByAppendingString: Title];
|
||||||
|
id QuitMenuItem = [[NSMenuItem alloc] initWithTitle: QuitTitle action: @selector(terminate:) keyEquivalent: @"q"];
|
||||||
|
[AppMenu addItem: QuitMenuItem];
|
||||||
|
[AppMenuItem setSubmenu: AppMenu];
|
||||||
|
|
||||||
|
[App activateIgnoringOtherApps: YES];
|
||||||
|
|
||||||
|
return Window;
|
||||||
|
}
|
Loading…
Reference in New Issue