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