cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_cocoaopengl.m (12745B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23/* NSOpenGL implementation of SDL OpenGL support */
     24
     25#if SDL_VIDEO_OPENGL_CGL
     26#include "SDL_cocoavideo.h"
     27#include "SDL_cocoaopengl.h"
     28
     29#include <OpenGL/CGLTypes.h>
     30#include <OpenGL/OpenGL.h>
     31#include <OpenGL/CGLRenderers.h>
     32
     33#include "SDL_loadso.h"
     34#include "SDL_opengl.h"
     35
     36#define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
     37
     38@implementation SDLOpenGLContext : NSOpenGLContext
     39
     40- (id)initWithFormat:(NSOpenGLPixelFormat *)format
     41        shareContext:(NSOpenGLContext *)share
     42{
     43    self = [super initWithFormat:format shareContext:share];
     44    if (self) {
     45        SDL_AtomicSet(&self->dirty, 0);
     46        self->window = NULL;
     47    }
     48    return self;
     49}
     50
     51- (void)scheduleUpdate
     52{
     53    SDL_AtomicAdd(&self->dirty, 1);
     54}
     55
     56/* This should only be called on the thread on which a user is using the context. */
     57- (void)updateIfNeeded
     58{
     59    int value = SDL_AtomicSet(&self->dirty, 0);
     60    if (value > 0) {
     61        /* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */
     62        [super update];
     63    }
     64}
     65
     66/* This should only be called on the thread on which a user is using the context. */
     67- (void)update
     68{
     69    /* This ensures that regular 'update' calls clear the atomic dirty flag. */
     70    [self scheduleUpdate];
     71    [self updateIfNeeded];
     72}
     73
     74/* Updates the drawable for the contexts and manages related state. */
     75- (void)setWindow:(SDL_Window *)newWindow
     76{
     77    if (self->window) {
     78        SDL_WindowData *oldwindowdata = (SDL_WindowData *)self->window->driverdata;
     79
     80        /* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */
     81        NSMutableArray *contexts = oldwindowdata->nscontexts;
     82        @synchronized (contexts) {
     83            [contexts removeObject:self];
     84        }
     85    }
     86
     87    self->window = newWindow;
     88
     89    if (newWindow) {
     90        SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
     91
     92        /* Now sign up for scheduled updates for the new window. */
     93        NSMutableArray *contexts = windowdata->nscontexts;
     94        @synchronized (contexts) {
     95            [contexts addObject:self];
     96        }
     97
     98        if ([self view] != [windowdata->nswindow contentView]) {
     99            [self setView:[windowdata->nswindow contentView]];
    100            if (self == [NSOpenGLContext currentContext]) {
    101                [self update];
    102            } else {
    103                [self scheduleUpdate];
    104            }
    105        }
    106    } else {
    107        [self clearDrawable];
    108        if (self == [NSOpenGLContext currentContext]) {
    109            [self update];
    110        } else {
    111            [self scheduleUpdate];
    112        }
    113    }
    114}
    115
    116@end
    117
    118
    119int
    120Cocoa_GL_LoadLibrary(_THIS, const char *path)
    121{
    122    /* Load the OpenGL library */
    123    if (path == NULL) {
    124        path = SDL_getenv("SDL_OPENGL_LIBRARY");
    125    }
    126    if (path == NULL) {
    127        path = DEFAULT_OPENGL;
    128    }
    129    _this->gl_config.dll_handle = SDL_LoadObject(path);
    130    if (!_this->gl_config.dll_handle) {
    131        return -1;
    132    }
    133    SDL_strlcpy(_this->gl_config.driver_path, path,
    134                SDL_arraysize(_this->gl_config.driver_path));
    135    return 0;
    136}
    137
    138void *
    139Cocoa_GL_GetProcAddress(_THIS, const char *proc)
    140{
    141    return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
    142}
    143
    144void
    145Cocoa_GL_UnloadLibrary(_THIS)
    146{
    147    SDL_UnloadObject(_this->gl_config.dll_handle);
    148    _this->gl_config.dll_handle = NULL;
    149}
    150
    151SDL_GLContext
    152Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
    153{
    154    NSAutoreleasePool *pool;
    155    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
    156    SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
    157    SDL_bool lion_or_later = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
    158    NSOpenGLPixelFormatAttribute attr[32];
    159    NSOpenGLPixelFormat *fmt;
    160    SDLOpenGLContext *context;
    161    NSOpenGLContext *share_context = nil;
    162    int i = 0;
    163    const char *glversion;
    164    int glversion_major;
    165    int glversion_minor;
    166
    167    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
    168        SDL_SetError ("OpenGL ES is not supported on this platform");
    169        return NULL;
    170    }
    171    if ((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) && !lion_or_later) {
    172        SDL_SetError ("OpenGL Core Profile is not supported on this platform version");
    173        return NULL;
    174    }
    175
    176    pool = [[NSAutoreleasePool alloc] init];
    177
    178    /* specify a profile if we're on Lion (10.7) or later. */
    179    if (lion_or_later) {
    180        NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy;
    181        if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
    182            profile = NSOpenGLProfileVersion3_2Core;
    183        }
    184        attr[i++] = NSOpenGLPFAOpenGLProfile;
    185        attr[i++] = profile;
    186    }
    187
    188    attr[i++] = NSOpenGLPFAColorSize;
    189    attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
    190
    191    attr[i++] = NSOpenGLPFADepthSize;
    192    attr[i++] = _this->gl_config.depth_size;
    193
    194    if (_this->gl_config.double_buffer) {
    195        attr[i++] = NSOpenGLPFADoubleBuffer;
    196    }
    197
    198    if (_this->gl_config.stereo) {
    199        attr[i++] = NSOpenGLPFAStereo;
    200    }
    201
    202    if (_this->gl_config.stencil_size) {
    203        attr[i++] = NSOpenGLPFAStencilSize;
    204        attr[i++] = _this->gl_config.stencil_size;
    205    }
    206
    207    if ((_this->gl_config.accum_red_size +
    208         _this->gl_config.accum_green_size +
    209         _this->gl_config.accum_blue_size +
    210         _this->gl_config.accum_alpha_size) > 0) {
    211        attr[i++] = NSOpenGLPFAAccumSize;
    212        attr[i++] = _this->gl_config.accum_red_size + _this->gl_config.accum_green_size + _this->gl_config.accum_blue_size + _this->gl_config.accum_alpha_size;
    213    }
    214
    215    if (_this->gl_config.multisamplebuffers) {
    216        attr[i++] = NSOpenGLPFASampleBuffers;
    217        attr[i++] = _this->gl_config.multisamplebuffers;
    218    }
    219
    220    if (_this->gl_config.multisamplesamples) {
    221        attr[i++] = NSOpenGLPFASamples;
    222        attr[i++] = _this->gl_config.multisamplesamples;
    223        attr[i++] = NSOpenGLPFANoRecovery;
    224    }
    225
    226    if (_this->gl_config.accelerated >= 0) {
    227        if (_this->gl_config.accelerated) {
    228            attr[i++] = NSOpenGLPFAAccelerated;
    229        } else {
    230            attr[i++] = NSOpenGLPFARendererID;
    231            attr[i++] = kCGLRendererGenericFloatID;
    232        }
    233    }
    234
    235    attr[i++] = NSOpenGLPFAScreenMask;
    236    attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
    237    attr[i] = 0;
    238
    239    fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
    240    if (fmt == nil) {
    241        SDL_SetError("Failed creating OpenGL pixel format");
    242        [pool release];
    243        return NULL;
    244    }
    245
    246    if (_this->gl_config.share_with_current_context) {
    247        share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
    248    }
    249
    250    context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
    251
    252    [fmt release];
    253
    254    if (context == nil) {
    255        SDL_SetError("Failed creating OpenGL context");
    256        [pool release];
    257        return NULL;
    258    }
    259
    260    [pool release];
    261
    262    if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
    263        Cocoa_GL_DeleteContext(_this, context);
    264        SDL_SetError("Failed making OpenGL context current");
    265        return NULL;
    266    }
    267
    268    if (_this->gl_config.major_version < 3 &&
    269        _this->gl_config.profile_mask == 0 &&
    270        _this->gl_config.flags == 0) {
    271        /* This is a legacy profile, so to match other backends, we're done. */
    272    } else {
    273        const GLubyte *(APIENTRY * glGetStringFunc)(GLenum);
    274
    275        glGetStringFunc = (const GLubyte *(APIENTRY *)(GLenum)) SDL_GL_GetProcAddress("glGetString");
    276        if (!glGetStringFunc) {
    277            Cocoa_GL_DeleteContext(_this, context);
    278            SDL_SetError ("Failed getting OpenGL glGetString entry point");
    279            return NULL;
    280        }
    281
    282        glversion = (const char *)glGetStringFunc(GL_VERSION);
    283        if (glversion == NULL) {
    284            Cocoa_GL_DeleteContext(_this, context);
    285            SDL_SetError ("Failed getting OpenGL context version");
    286            return NULL;
    287        }
    288
    289        if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) {
    290            Cocoa_GL_DeleteContext(_this, context);
    291            SDL_SetError ("Failed parsing OpenGL context version");
    292            return NULL;
    293        }
    294
    295        if ((glversion_major < _this->gl_config.major_version) ||
    296           ((glversion_major == _this->gl_config.major_version) && (glversion_minor < _this->gl_config.minor_version))) {
    297            Cocoa_GL_DeleteContext(_this, context);
    298            SDL_SetError ("Failed creating OpenGL context at version requested");
    299            return NULL;
    300        }
    301
    302        /* In the future we'll want to do this, but to match other platforms
    303           we'll leave the OpenGL version the way it is for now
    304         */
    305        /*_this->gl_config.major_version = glversion_major;*/
    306        /*_this->gl_config.minor_version = glversion_minor;*/
    307    }
    308    return context;
    309}
    310
    311int
    312Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
    313{
    314    NSAutoreleasePool *pool;
    315
    316    pool = [[NSAutoreleasePool alloc] init];
    317
    318    if (context) {
    319        SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
    320        [nscontext setWindow:window];
    321        [nscontext updateIfNeeded];
    322        [nscontext makeCurrentContext];
    323    } else {
    324        [NSOpenGLContext clearCurrentContext];
    325    }
    326
    327    [pool release];
    328    return 0;
    329}
    330
    331void
    332Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
    333{
    334    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
    335    NSView *contentView = [windata->nswindow contentView];
    336    NSRect viewport = [contentView bounds];
    337
    338    /* This gives us the correct viewport for a Retina-enabled view, only
    339     * supported on 10.7+. */
    340    if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
    341        viewport = [contentView convertRectToBacking:viewport];
    342    }
    343
    344    if (w) {
    345        *w = viewport.size.width;
    346    }
    347
    348    if (h) {
    349        *h = viewport.size.height;
    350    }
    351}
    352
    353int
    354Cocoa_GL_SetSwapInterval(_THIS, int interval)
    355{
    356    NSAutoreleasePool *pool;
    357    NSOpenGLContext *nscontext;
    358    GLint value;
    359    int status;
    360
    361    if (interval < 0) {  /* no extension for this on Mac OS X at the moment. */
    362        return SDL_SetError("Late swap tearing currently unsupported");
    363    }
    364
    365    pool = [[NSAutoreleasePool alloc] init];
    366
    367    nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
    368    if (nscontext != nil) {
    369        value = interval;
    370        [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
    371        status = 0;
    372    } else {
    373        status = SDL_SetError("No current OpenGL context");
    374    }
    375
    376    [pool release];
    377    return status;
    378}
    379
    380int
    381Cocoa_GL_GetSwapInterval(_THIS)
    382{
    383    NSAutoreleasePool *pool;
    384    NSOpenGLContext *nscontext;
    385    GLint value;
    386    int status = 0;
    387
    388    pool = [[NSAutoreleasePool alloc] init];
    389
    390    nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
    391    if (nscontext != nil) {
    392        [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
    393        status = (int)value;
    394    }
    395
    396    [pool release];
    397    return status;
    398}
    399
    400void
    401Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
    402{
    403    NSAutoreleasePool *pool;
    404
    405    pool = [[NSAutoreleasePool alloc] init];
    406
    407    SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext();
    408    [nscontext flushBuffer];
    409    [nscontext updateIfNeeded];
    410
    411    [pool release];
    412}
    413
    414void
    415Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
    416{
    417    NSAutoreleasePool *pool;
    418    SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
    419
    420    pool = [[NSAutoreleasePool alloc] init];
    421
    422    [nscontext setWindow:NULL];
    423    [nscontext release];
    424
    425    [pool release];
    426}
    427
    428#endif /* SDL_VIDEO_OPENGL_CGL */
    429
    430/* vi: set ts=4 sw=4 expandtab: */