src/video/quartz/SDL_QuartzVideo.m
author Sam Lantinga
Fri, 08 Aug 2003 15:01:14 +0000
changeset 668 f91ded895274
parent 657 714053f573e7
child 674 be597a247e20
permissions -rw-r--r--
*** empty log message ***
slouken@47
     1
/*
slouken@47
     2
    SDL - Simple DirectMedia Layer
slouken@297
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
slouken@47
     4
slouken@47
     5
    This library is free software; you can redistribute it and/or
slouken@47
     6
    modify it under the terms of the GNU Library General Public
slouken@47
     7
    License as published by the Free Software Foundation; either
slouken@47
     8
    version 2 of the License, or (at your option) any later version.
slouken@47
     9
slouken@47
    10
    This library is distributed in the hope that it will be useful,
slouken@47
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@47
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@47
    13
    Library General Public License for more details.
slouken@47
    14
slouken@47
    15
    You should have received a copy of the GNU Library General Public
slouken@47
    16
    License along with this library; if not, write to the Free
slouken@47
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@47
    18
slouken@47
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@47
    21
*/
slouken@47
    22
slouken@47
    23
#include "SDL_QuartzVideo.h"
slouken@47
    24
slouken@47
    25
/* Include files into one compile unit...break apart eventually */
slouken@47
    26
#include "SDL_QuartzWM.m"
slouken@47
    27
#include "SDL_QuartzEvents.m"
slouken@47
    28
#include "SDL_QuartzWindow.m"
slouken@47
    29
slouken@47
    30
/* Bootstrap binding, enables entry point into the driver */
slouken@47
    31
VideoBootStrap QZ_bootstrap = {
slouken@272
    32
    "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
slouken@47
    33
};
slouken@47
    34
slouken@588
    35
slouken@47
    36
/* Bootstrap functions */
slouken@47
    37
static int QZ_Available () {
slouken@47
    38
    return 1;
slouken@47
    39
}
slouken@47
    40
slouken@47
    41
static SDL_VideoDevice* QZ_CreateDevice (int device_index) {
slouken@47
    42
slouken@272
    43
#pragma unused (device_index)
slouken@47
    44
slouken@47
    45
    SDL_VideoDevice *device;
slouken@47
    46
    SDL_PrivateVideoData *hidden;
slouken@47
    47
slouken@47
    48
    device = (SDL_VideoDevice*) malloc (sizeof (*device) );
slouken@47
    49
    hidden = (SDL_PrivateVideoData*) malloc (sizeof (*hidden) );
slouken@47
    50
slouken@47
    51
    if (device == NULL || hidden == NULL)
slouken@47
    52
        SDL_OutOfMemory ();
slouken@47
    53
slouken@47
    54
    memset (device, 0, sizeof (*device) );
slouken@47
    55
    memset (hidden, 0, sizeof (*hidden) );
slouken@272
    56
slouken@47
    57
    device->hidden = hidden;
slouken@47
    58
slouken@47
    59
    device->VideoInit        = QZ_VideoInit;
slouken@47
    60
    device->ListModes        = QZ_ListModes;
slouken@47
    61
    device->SetVideoMode     = QZ_SetVideoMode;
slouken@47
    62
    device->ToggleFullScreen = QZ_ToggleFullScreen;
slouken@47
    63
    device->SetColors        = QZ_SetColors;
slouken@47
    64
    /* device->UpdateRects      = QZ_UpdateRects; this is determined by SetVideoMode() */
slouken@47
    65
    device->VideoQuit        = QZ_VideoQuit;
slouken@272
    66
slouken@47
    67
    device->LockHWSurface   = QZ_LockHWSurface;
slouken@47
    68
    device->UnlockHWSurface = QZ_UnlockHWSurface;
slouken@47
    69
    device->FreeHWSurface   = QZ_FreeHWSurface;
slouken@47
    70
    /* device->FlipHWSurface   = QZ_FlipHWSurface */;
slouken@47
    71
slouken@47
    72
    device->SetGamma     = QZ_SetGamma;
slouken@47
    73
    device->GetGamma     = QZ_GetGamma;
slouken@47
    74
    device->SetGammaRamp = QZ_SetGammaRamp;
slouken@47
    75
    device->GetGammaRamp = QZ_GetGammaRamp;
slouken@47
    76
slouken@47
    77
    device->GL_GetProcAddress = QZ_GL_GetProcAddress;
slouken@47
    78
    device->GL_GetAttribute   = QZ_GL_GetAttribute;
slouken@47
    79
    device->GL_MakeCurrent    = QZ_GL_MakeCurrent;
slouken@47
    80
    device->GL_SwapBuffers    = QZ_GL_SwapBuffers;
slouken@47
    81
    device->GL_LoadLibrary    = QZ_GL_LoadLibrary;
slouken@272
    82
slouken@47
    83
    device->FreeWMCursor   = QZ_FreeWMCursor;
slouken@47
    84
    device->CreateWMCursor = QZ_CreateWMCursor;
slouken@47
    85
    device->ShowWMCursor   = QZ_ShowWMCursor;
slouken@47
    86
    device->WarpWMCursor   = QZ_WarpWMCursor;
slouken@47
    87
    device->MoveWMCursor   = QZ_MoveWMCursor;
slouken@47
    88
    device->CheckMouseMode = QZ_CheckMouseMode;
slouken@47
    89
    device->InitOSKeymap   = QZ_InitOSKeymap;
slouken@47
    90
    device->PumpEvents     = QZ_PumpEvents;
slouken@47
    91
slouken@47
    92
    device->SetCaption    = QZ_SetCaption;
slouken@47
    93
    device->SetIcon       = QZ_SetIcon;
slouken@47
    94
    device->IconifyWindow = QZ_IconifyWindow;
slouken@47
    95
    /*device->GetWMInfo     = QZ_GetWMInfo;*/
slouken@47
    96
    device->GrabInput     = QZ_GrabInput;
slouken@272
    97
slouken@390
    98
    device->CreateYUVOverlay =  QZ_CreateYUVOverlay;
slouken@390
    99
slouken@390
   100
    device->free             = QZ_DeleteDevice;
slouken@272
   101
slouken@47
   102
    return device;
slouken@47
   103
}
slouken@47
   104
slouken@47
   105
static void QZ_DeleteDevice (SDL_VideoDevice *device) {
slouken@47
   106
slouken@47
   107
    free (device->hidden);
slouken@47
   108
    free (device);
slouken@47
   109
}
slouken@47
   110
slouken@47
   111
static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) {
slouken@47
   112
slouken@272
   113
    /* Initialize the video settings; this data persists between mode switches */
slouken@272
   114
    display_id = kCGDirectMainDisplay;
slouken@272
   115
    save_mode  = CGDisplayCurrentMode    (display_id);
slouken@272
   116
    mode_list  = CGDisplayAvailableModes (display_id);
slouken@272
   117
    palette    = CGPaletteCreateDefaultColorPalette ();
slouken@272
   118
slouken@272
   119
    /* Gather some information that is useful to know about the display */
slouken@272
   120
    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel),
slouken@272
   121
                      kCFNumberSInt32Type, &device_bpp);
slouken@47
   122
slouken@272
   123
    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
slouken@272
   124
                      kCFNumberSInt32Type, &device_width);
slouken@47
   125
slouken@272
   126
    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
slouken@272
   127
                      kCFNumberSInt32Type, &device_height);
slouken@272
   128
slouken@272
   129
    video_format->BitsPerPixel = device_bpp;
slouken@272
   130
slouken@501
   131
    /* Set misc globals */
slouken@501
   132
    current_grab_mode = SDL_GRAB_OFF;
slouken@501
   133
    in_foreground     = YES;
icculus@563
   134
    cursor_visible    = YES;
slouken@501
   135
    
slouken@555
   136
    /* register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE */
slouken@555
   137
    QZ_RegisterForSleepNotifications (this);
slouken@555
   138
    
slouken@272
   139
    return 0;
slouken@47
   140
}
slouken@47
   141
slouken@47
   142
static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
slouken@390
   143
slouken@272
   144
    CFIndex num_modes;
slouken@47
   145
    CFIndex i;
slouken@47
   146
slouken@47
   147
    int list_size = 0;
slouken@390
   148
slouken@47
   149
    /* Any windowed mode is acceptable */
slouken@47
   150
    if ( (flags & SDL_FULLSCREEN) == 0 )
slouken@47
   151
        return (SDL_Rect**)-1;
slouken@390
   152
slouken@47
   153
    /* Free memory from previous call, if any */
slouken@501
   154
    if ( client_mode_list != NULL ) {
slouken@47
   155
slouken@390
   156
        int i;
slouken@47
   157
slouken@501
   158
        for (i = 0; client_mode_list[i] != NULL; i++)
slouken@501
   159
            free (client_mode_list[i]);
slouken@47
   160
slouken@501
   161
        free (client_mode_list);
slouken@501
   162
        client_mode_list = NULL;
slouken@47
   163
    }
slouken@390
   164
slouken@272
   165
    num_modes = CFArrayGetCount (mode_list);
slouken@272
   166
slouken@47
   167
    /* Build list of modes with the requested bpp */
slouken@155
   168
    for (i = 0; i < num_modes; i++) {
slouken@390
   169
slouken@155
   170
        CFDictionaryRef onemode;
slouken@155
   171
        CFNumberRef     number;
slouken@390
   172
        int bpp;
slouken@390
   173
slouken@390
   174
        onemode = CFArrayGetValueAtIndex (mode_list, i);
slouken@390
   175
        number = CFDictionaryGetValue (onemode, kCGDisplayBitsPerPixel);
slouken@390
   176
        CFNumberGetValue (number, kCFNumberSInt32Type, &bpp);
slouken@390
   177
slouken@390
   178
        if (bpp == format->BitsPerPixel) {
slouken@390
   179
slouken@390
   180
            int intvalue;
slouken@390
   181
            int hasMode;
slouken@390
   182
            int width, height;
slouken@47
   183
slouken@390
   184
            number = CFDictionaryGetValue (onemode, kCGDisplayWidth);
slouken@390
   185
            CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
slouken@390
   186
            width = (Uint16) intvalue;
slouken@390
   187
slouken@390
   188
            number = CFDictionaryGetValue (onemode, kCGDisplayHeight);
slouken@390
   189
            CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
slouken@390
   190
            height = (Uint16) intvalue;
slouken@390
   191
slouken@390
   192
            /* Check if mode is already in the list */
slouken@390
   193
            {
slouken@390
   194
                int i;
slouken@390
   195
                hasMode = SDL_FALSE;
slouken@390
   196
                for (i = 0; i < list_size; i++) {
slouken@501
   197
                    if (client_mode_list[i]->w == width && 
slouken@501
   198
                        client_mode_list[i]->h == height) {
slouken@390
   199
                        hasMode = SDL_TRUE;
slouken@390
   200
                        break;
slouken@390
   201
                    }
slouken@155
   202
                }
slouken@155
   203
            }
slouken@390
   204
slouken@390
   205
            /* Grow the list and add mode to the list */
slouken@390
   206
            if ( ! hasMode ) {
slouken@390
   207
slouken@390
   208
                SDL_Rect *rect;
slouken@390
   209
slouken@390
   210
                list_size++;
slouken@390
   211
slouken@501
   212
                if (client_mode_list == NULL)
slouken@501
   213
                    client_mode_list = (SDL_Rect**) 
slouken@501
   214
                        malloc (sizeof(*client_mode_list) * (list_size+1) );
slouken@390
   215
                else
slouken@501
   216
                    client_mode_list = (SDL_Rect**) 
slouken@501
   217
                        realloc (client_mode_list, sizeof(*client_mode_list) * (list_size+1));
slouken@390
   218
slouken@501
   219
                rect = (SDL_Rect*) malloc (sizeof(**client_mode_list));
slouken@47
   220
slouken@501
   221
                if (client_mode_list == NULL || rect == NULL) {
slouken@390
   222
                    SDL_OutOfMemory ();
slouken@390
   223
                    return NULL;
slouken@390
   224
                }
slouken@390
   225
slouken@390
   226
                rect->w = width;
slouken@390
   227
                rect->h = height;
slouken@390
   228
slouken@501
   229
                client_mode_list[list_size-1] = rect;
slouken@501
   230
                client_mode_list[list_size]   = NULL;
slouken@272
   231
            }
slouken@47
   232
        }
slouken@47
   233
    }
slouken@390
   234
slouken@155
   235
    /* Sort list largest to smallest (by area) */
slouken@155
   236
    {
slouken@155
   237
        int i, j;
slouken@155
   238
        for (i = 0; i < list_size; i++) {
slouken@155
   239
            for (j = 0; j < list_size-1; j++) {
slouken@390
   240
slouken@155
   241
                int area1, area2;
slouken@501
   242
                area1 = client_mode_list[j]->w * client_mode_list[j]->h;
slouken@501
   243
                area2 = client_mode_list[j+1]->w * client_mode_list[j+1]->h;
slouken@390
   244
slouken@155
   245
                if (area1 < area2) {
slouken@501
   246
                    SDL_Rect *tmp = client_mode_list[j];
slouken@501
   247
                    client_mode_list[j] = client_mode_list[j+1];
slouken@501
   248
                    client_mode_list[j+1] = tmp;
slouken@155
   249
                }
slouken@155
   250
            }
slouken@155
   251
        }
slouken@155
   252
    }
slouken@501
   253
    return client_mode_list;
slouken@47
   254
}
slouken@47
   255
slouken@657
   256
static SDL_bool QZ_WindowPosition(_THIS, int *x, int *y)
slouken@657
   257
{
slouken@657
   258
    const char *window = getenv("SDL_VIDEO_WINDOW_POS");
slouken@657
   259
    if ( window ) {
slouken@657
   260
        if ( sscanf(window, "%d,%d", x, y) == 2 ) {
slouken@657
   261
            return SDL_TRUE;
slouken@657
   262
        }
slouken@657
   263
    }
slouken@657
   264
    return SDL_FALSE;
slouken@657
   265
}
slouken@657
   266
slouken@501
   267
/* 
slouken@501
   268
    Gamma functions to try to hide the flash from a rez switch
slouken@501
   269
    Fade the display from normal to black
slouken@501
   270
    Save gamma tables for fade back to normal
slouken@501
   271
*/
slouken@272
   272
static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) {
slouken@272
   273
slouken@272
   274
    CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
slouken@272
   275
    greenTable[QZ_GAMMA_TABLE_SIZE],
slouken@272
   276
    blueTable[QZ_GAMMA_TABLE_SIZE];
slouken@272
   277
slouken@272
   278
    float percent;
slouken@272
   279
    int j;
slouken@272
   280
    int actual;
slouken@272
   281
slouken@272
   282
    if ( (CGDisplayNoErr != CGGetDisplayTransferByTable
slouken@272
   283
          (display_id, QZ_GAMMA_TABLE_SIZE,
slouken@272
   284
           table->red, table->green, table->blue, &actual)) ||
slouken@272
   285
         actual != QZ_GAMMA_TABLE_SIZE) {
slouken@272
   286
slouken@272
   287
        return 1;
slouken@272
   288
    }
slouken@272
   289
slouken@272
   290
    memcpy (redTable, table->red, sizeof(redTable));
slouken@272
   291
    memcpy (greenTable, table->green, sizeof(greenTable));
slouken@272
   292
    memcpy (blueTable, table->blue, sizeof(greenTable));
slouken@272
   293
slouken@272
   294
    for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
slouken@272
   295
slouken@272
   296
        for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
slouken@272
   297
slouken@272
   298
            redTable[j]   = redTable[j]   * percent;
slouken@272
   299
            greenTable[j] = greenTable[j] * percent;
slouken@272
   300
            blueTable[j]  = blueTable[j]  * percent;
slouken@272
   301
        }
slouken@272
   302
slouken@272
   303
        if (CGDisplayNoErr != CGSetDisplayTransferByTable
slouken@272
   304
            (display_id, QZ_GAMMA_TABLE_SIZE,
slouken@272
   305
             redTable, greenTable, blueTable)) {
slouken@272
   306
slouken@272
   307
            CGDisplayRestoreColorSyncSettings();
slouken@272
   308
            return 1;
slouken@272
   309
        }
slouken@272
   310
slouken@272
   311
        SDL_Delay (10);
slouken@272
   312
    }
slouken@272
   313
slouken@272
   314
    return 0;
slouken@272
   315
}
slouken@272
   316
slouken@501
   317
/* 
slouken@501
   318
    Fade the display from black to normal
slouken@501
   319
    Restore previously saved gamma values
slouken@501
   320
*/
slouken@272
   321
static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) {
slouken@272
   322
slouken@272
   323
    CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
slouken@390
   324
    greenTable[QZ_GAMMA_TABLE_SIZE],
slouken@390
   325
    blueTable[QZ_GAMMA_TABLE_SIZE];
slouken@272
   326
slouken@272
   327
    float percent;
slouken@272
   328
    int j;
slouken@272
   329
slouken@272
   330
    memset (redTable, 0, sizeof(redTable));
slouken@272
   331
    memset (greenTable, 0, sizeof(greenTable));
slouken@272
   332
    memset (blueTable, 0, sizeof(greenTable));
slouken@390
   333
slouken@272
   334
    for (percent = 0.0; percent <= 1.0; percent += 0.01) {
slouken@272
   335
slouken@272
   336
        for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
slouken@272
   337
slouken@272
   338
            redTable[j]   = table->red[j]   * percent;
slouken@272
   339
            greenTable[j] = table->green[j] * percent;
slouken@272
   340
            blueTable[j]  = table->blue[j]  * percent;
slouken@272
   341
        }
slouken@272
   342
slouken@272
   343
        if (CGDisplayNoErr != CGSetDisplayTransferByTable
slouken@272
   344
            (display_id, QZ_GAMMA_TABLE_SIZE,
slouken@272
   345
             redTable, greenTable, blueTable)) {
slouken@272
   346
slouken@272
   347
            CGDisplayRestoreColorSyncSettings();
slouken@272
   348
            return 1;
slouken@272
   349
        }
slouken@272
   350
slouken@272
   351
        SDL_Delay (10);
slouken@272
   352
    }
slouken@272
   353
slouken@272
   354
    return 0;
slouken@272
   355
}
slouken@272
   356
slouken@47
   357
static void QZ_UnsetVideoMode (_THIS) {
slouken@47
   358
slouken@47
   359
    /* Reset values that may change between switches */
slouken@501
   360
    this->info.blit_fill  = 0;
slouken@501
   361
    this->FillHWRect      = NULL;
slouken@501
   362
    this->UpdateRects     = NULL;
slouken@501
   363
    this->LockHWSurface   = NULL;
slouken@501
   364
    this->UnlockHWSurface = NULL;
slouken@501
   365
    
slouken@272
   366
    /* Release fullscreen resources */
slouken@47
   367
    if ( mode_flags & SDL_FULLSCREEN ) {
slouken@272
   368
slouken@272
   369
        SDL_QuartzGammaTable gamma_table;
slouken@272
   370
        int gamma_error;
slouken@435
   371
        NSRect screen_rect;
slouken@435
   372
        
slouken@272
   373
        gamma_error = QZ_FadeGammaOut (this, &gamma_table);
slouken@272
   374
slouken@588
   375
        /*  Release double buffer stuff */
slouken@588
   376
        if ( mode_flags & (SDL_HWSURFACE|SDL_DOUBLEBUF)) {
slouken@588
   377
            quit_thread = YES;
slouken@588
   378
            SDL_SemPost (sem1);
slouken@588
   379
            SDL_WaitThread (thread, NULL);
slouken@588
   380
            SDL_DestroySemaphore (sem1);
slouken@588
   381
            SDL_DestroySemaphore (sem2);
slouken@588
   382
            free (sw_buffers[0]);
slouken@588
   383
        }
slouken@588
   384
        
slouken@501
   385
        /* 
slouken@501
   386
            Release the OpenGL context
slouken@501
   387
            Do this first to avoid trash on the display before fade
slouken@501
   388
        */
slouken@501
   389
        if ( mode_flags & SDL_OPENGL ) {
slouken@501
   390
        
slouken@272
   391
            QZ_TearDownOpenGL (this);
slouken@501
   392
            CGLSetFullScreen (NULL);
slouken@501
   393
        }
slouken@501
   394
        
slouken@272
   395
        /* Restore original screen resolution/bpp */
slouken@47
   396
        CGDisplaySwitchToMode (display_id, save_mode);
slouken@588
   397
        CGReleaseAllDisplays ();
slouken@272
   398
        ShowMenuBar ();
slouken@390
   399
slouken@435
   400
        /* 
slouken@501
   401
            Reset the main screen's rectangle
slouken@501
   402
            See comment in QZ_SetVideoFullscreen for why we do this
slouken@435
   403
        */
slouken@435
   404
        screen_rect = NSMakeRect(0,0,device_width,device_height);
slouken@435
   405
        [ [ NSScreen mainScreen ] setFrame:screen_rect ];
slouken@435
   406
        
slouken@272
   407
        if (! gamma_error)
slouken@272
   408
            QZ_FadeGammaIn (this, &gamma_table);
slouken@47
   409
    }
slouken@272
   410
    /* Release window mode resources */
slouken@390
   411
    else {
slouken@501
   412
        
slouken@158
   413
        [ qz_window close ];
slouken@272
   414
        [ qz_window release ];
slouken@390
   415
        qz_window = nil;
slouken@501
   416
        window_view = nil;
slouken@501
   417
        
slouken@272
   418
        /* Release the OpenGL context */
slouken@272
   419
        if ( mode_flags & SDL_OPENGL )
slouken@272
   420
            QZ_TearDownOpenGL (this);
slouken@47
   421
    }
slouken@272
   422
slouken@155
   423
    /* Signal successful teardown */
slouken@155
   424
    video_set = SDL_FALSE;
slouken@47
   425
}
slouken@47
   426
slouken@47
   427
static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
slouken@47
   428
                                           int height, int bpp, Uint32 flags) {
slouken@47
   429
    int exact_match;
slouken@272
   430
    int gamma_error;
slouken@272
   431
    SDL_QuartzGammaTable gamma_table;
slouken@435
   432
    NSRect screen_rect;
slouken@588
   433
    CGError error;
slouken@435
   434
    
slouken@501
   435
    /* Destroy any previous mode */
slouken@501
   436
    if (video_set == SDL_TRUE)
slouken@501
   437
        QZ_UnsetVideoMode (this);
slouken@501
   438
slouken@47
   439
    /* See if requested mode exists */
slouken@390
   440
    mode = CGDisplayBestModeForParameters (display_id, bpp, width,
slouken@390
   441
                                           height, &exact_match);
slouken@390
   442
slouken@47
   443
    /* Require an exact match to the requested mode */
slouken@47
   444
    if ( ! exact_match ) {
slouken@501
   445
        SDL_SetError ("Failed to find display resolution: %dx%dx%d", width, height, bpp);
slouken@47
   446
        goto ERR_NO_MATCH;
slouken@47
   447
    }
slouken@155
   448
slouken@272
   449
    /* Fade display to zero gamma */
slouken@272
   450
    gamma_error = QZ_FadeGammaOut (this, &gamma_table);
slouken@272
   451
slouken@47
   452
    /* Put up the blanking window (a window above all other windows) */
slouken@588
   453
    if (getenv ("SDL_SINGLEDISPLAY"))
slouken@588
   454
        error = CGDisplayCapture (display_id);
slouken@588
   455
    else
slouken@588
   456
        error = CGCaptureAllDisplays ();
slouken@588
   457
        
slouken@588
   458
    if ( CGDisplayNoErr != error ) {
slouken@47
   459
        SDL_SetError ("Failed capturing display");
slouken@47
   460
        goto ERR_NO_CAPTURE;
slouken@47
   461
    }
slouken@272
   462
slouken@47
   463
    /* Do the physical switch */
slouken@47
   464
    if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
slouken@47
   465
        SDL_SetError ("Failed switching display resolution");
slouken@47
   466
        goto ERR_NO_SWITCH;
slouken@47
   467
    }
slouken@272
   468
slouken@47
   469
    current->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
slouken@47
   470
    current->pitch  = CGDisplayBytesPerRow (display_id);
slouken@47
   471
slouken@58
   472
    current->flags = 0;
slouken@47
   473
    current->w = width;
slouken@47
   474
    current->h = height;
slouken@390
   475
    current->flags |= SDL_FULLSCREEN;
slouken@47
   476
    current->flags |= SDL_HWSURFACE;
slouken@501
   477
    current->flags |= SDL_PREALLOC;
slouken@501
   478
    
slouken@501
   479
    this->UpdateRects     = QZ_DirectUpdate;
slouken@501
   480
    this->LockHWSurface   = QZ_LockHWSurface;
slouken@501
   481
    this->UnlockHWSurface = QZ_UnlockHWSurface;
slouken@588
   482
slouken@588
   483
    /* Setup double-buffer emulation */
slouken@588
   484
    if ( flags & SDL_DOUBLEBUF ) {
slouken@588
   485
        
slouken@588
   486
        /*
slouken@588
   487
            Setup a software backing store for reasonable results when
slouken@588
   488
            double buffering is requested (since a single-buffered hardware
slouken@588
   489
            surface looks hideous).
slouken@588
   490
            
slouken@588
   491
            The actual screen blit occurs in a separate thread to allow 
slouken@588
   492
            other blitting while waiting on the VBL (and hence results in higher framerates).
slouken@588
   493
        */
slouken@588
   494
        this->LockHWSurface = NULL;
slouken@588
   495
        this->UnlockHWSurface = NULL;
slouken@588
   496
        this->UpdateRects = NULL;
slouken@588
   497
        
slouken@588
   498
        current->flags |= (SDL_HWSURFACE|SDL_DOUBLEBUF);
slouken@588
   499
        this->UpdateRects = QZ_DoubleBufferUpdate;
slouken@588
   500
        this->LockHWSurface = QZ_LockDoubleBuffer;
slouken@588
   501
        this->UnlockHWSurface = QZ_UnlockDoubleBuffer;
slouken@588
   502
        this->FlipHWSurface = QZ_FlipDoubleBuffer;
slouken@588
   503
slouken@588
   504
        current->pixels = malloc (current->pitch * current->h * 2);
slouken@588
   505
        if (current->pixels == NULL) {
slouken@588
   506
            SDL_OutOfMemory ();
slouken@588
   507
            goto ERR_DOUBLEBUF;
slouken@588
   508
        }
slouken@588
   509
        
slouken@588
   510
        sw_buffers[0] = current->pixels;
slouken@588
   511
        sw_buffers[1] = (Uint8*)current->pixels + current->pitch * current->h;
slouken@588
   512
        
slouken@588
   513
        quit_thread = NO;
slouken@588
   514
        sem1 = SDL_CreateSemaphore (0);
slouken@588
   515
        sem2 = SDL_CreateSemaphore (1);
slouken@588
   516
        thread = SDL_CreateThread ((int (*)(void *))QZ_ThreadFlip, this);
slouken@47
   517
    }
slouken@390
   518
slouken@47
   519
    if ( CGDisplayCanSetPalette (display_id) )
slouken@47
   520
        current->flags |= SDL_HWPALETTE;
slouken@390
   521
slouken@47
   522
    /* Setup OpenGL for a fullscreen context */
slouken@47
   523
    if (flags & SDL_OPENGL) {
slouken@47
   524
slouken@47
   525
        CGLError err;
slouken@47
   526
        CGLContextObj ctx;
slouken@390
   527
slouken@47
   528
        if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
slouken@272
   529
            goto ERR_NO_GL;
slouken@47
   530
        }
slouken@390
   531
slouken@47
   532
        ctx = [ gl_context cglContext ];
slouken@47
   533
        err = CGLSetFullScreen (ctx);
slouken@390
   534
slouken@47
   535
        if (err) {
slouken@501
   536
            SDL_SetError ("Error setting OpenGL fullscreen: %s", CGLErrorString(err));
slouken@47
   537
            goto ERR_NO_GL;
slouken@47
   538
        }
slouken@390
   539
slouken@47
   540
        [ gl_context makeCurrentContext];
slouken@272
   541
slouken@272
   542
        glClear (GL_COLOR_BUFFER_BIT);
slouken@272
   543
slouken@272
   544
        [ gl_context flushBuffer ];
slouken@390
   545
slouken@47
   546
        current->flags |= SDL_OPENGL;
slouken@47
   547
    }
slouken@47
   548
slouken@47
   549
    /* If we don't hide menu bar, it will get events and interrupt the program */
slouken@47
   550
    HideMenuBar ();
slouken@272
   551
slouken@272
   552
    /* Fade the display to original gamma */
slouken@272
   553
    if (! gamma_error )
slouken@272
   554
        QZ_FadeGammaIn (this, &gamma_table);
slouken@390
   555
slouken@435
   556
    /* 
slouken@501
   557
        There is a bug in Cocoa where NSScreen doesn't synchronize
slouken@501
   558
        with CGDirectDisplay, so the main screen's frame is wrong.
slouken@501
   559
        As a result, coordinate translation produces incorrect results.
slouken@501
   560
        We can hack around this bug by setting the screen rect
slouken@501
   561
        ourselves. This hack should be removed if/when the bug is fixed.
slouken@435
   562
    */
slouken@435
   563
    screen_rect = NSMakeRect(0,0,width,height);
slouken@435
   564
    [ [ NSScreen mainScreen ] setFrame:screen_rect ]; 
slouken@435
   565
slouken@47
   566
    /* Save the flags to ensure correct tear-down */
slouken@47
   567
    mode_flags = current->flags;
slouken@390
   568
slouken@47
   569
    return current;
slouken@47
   570
slouken@390
   571
    /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
slouken@588
   572
ERR_NO_GL:      
slouken@588
   573
ERR_DOUBLEBUF:  CGDisplaySwitchToMode (display_id, save_mode);
slouken@588
   574
ERR_NO_SWITCH:  CGReleaseAllDisplays ();
slouken@390
   575
ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); }
slouken@588
   576
ERR_NO_MATCH:   return NULL;
slouken@47
   577
}
slouken@47
   578
slouken@47
   579
static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width,
slouken@390
   580
                                         int height, int bpp, Uint32 flags) {
slouken@58
   581
    unsigned int style;
slouken@501
   582
    NSRect contentRect;
slouken@657
   583
    int center_window = 1;
slouken@657
   584
    int origin_x, origin_y;
slouken@390
   585
slouken@58
   586
    current->flags = 0;
slouken@58
   587
    current->w = width;
slouken@47
   588
    current->h = height;
slouken@501
   589
    
slouken@501
   590
    contentRect = NSMakeRect (0, 0, width, height);
slouken@501
   591
    
slouken@501
   592
    /*
slouken@501
   593
        Check if we should completely destroy the previous mode 
slouken@501
   594
        - If it is fullscreen
slouken@501
   595
        - If it has different noframe or resizable attribute
slouken@501
   596
        - If it is OpenGL (since gl attributes could be different)
slouken@501
   597
        - If new mode is OpenGL, but previous mode wasn't
slouken@501
   598
    */
slouken@501
   599
    if (video_set == SDL_TRUE)
slouken@501
   600
        if ( (mode_flags & SDL_FULLSCREEN) ||
slouken@501
   601
             ((mode_flags ^ flags) & (SDL_NOFRAME|SDL_RESIZABLE)) ||
slouken@501
   602
             (mode_flags & SDL_OPENGL) || 
slouken@501
   603
             (flags & SDL_OPENGL) )
slouken@501
   604
            QZ_UnsetVideoMode (this);
slouken@501
   605
        
slouken@501
   606
    /* Check if we should recreate the window */
slouken@501
   607
    if (qz_window == nil) {
slouken@501
   608
    
slouken@501
   609
        /* Set the window style based on input flags */
slouken@501
   610
        if ( flags & SDL_NOFRAME ) {
slouken@501
   611
            style = NSBorderlessWindowMask;
slouken@501
   612
            current->flags |= SDL_NOFRAME;
slouken@501
   613
        } else {
slouken@501
   614
            style = NSTitledWindowMask;
slouken@501
   615
            style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
slouken@501
   616
            if ( flags & SDL_RESIZABLE ) {
slouken@501
   617
                style |= NSResizableWindowMask;
slouken@501
   618
                current->flags |= SDL_RESIZABLE;
slouken@501
   619
            }
slouken@501
   620
        }
slouken@501
   621
                
slouken@657
   622
        if ( QZ_WindowPosition(this, &origin_x, &origin_y) ) {
slouken@657
   623
            center_window = 0;
slouken@657
   624
            contentRect.origin.x = (float)origin_x;
slouken@657
   625
            contentRect.origin.y = (float)origin_y;            
slouken@657
   626
        }
slouken@657
   627
        
slouken@501
   628
        /* Manually create a window, avoids having a nib file resource */
slouken@501
   629
        qz_window = [ [ SDL_QuartzWindow alloc ] 
slouken@501
   630
            initWithContentRect:contentRect
slouken@501
   631
                styleMask:style 
slouken@501
   632
                    backing:NSBackingStoreBuffered
slouken@501
   633
                        defer:NO ];
slouken@501
   634
                          
slouken@501
   635
        if (qz_window == nil) {
slouken@501
   636
            SDL_SetError ("Could not create the Cocoa window");
slouken@501
   637
            return NULL;
slouken@501
   638
        }
slouken@501
   639
    
icculus@560
   640
        //[ qz_window setReleasedWhenClosed:YES ];
slouken@501
   641
        QZ_SetCaption(this, this->wm_title, this->wm_icon);
slouken@501
   642
        [ qz_window setAcceptsMouseMovedEvents:YES ];
slouken@501
   643
        [ qz_window setViewsNeedDisplay:NO ];
slouken@657
   644
        if ( center_window ) {
slouken@657
   645
            [ qz_window center ];
slouken@657
   646
        }
slouken@501
   647
        [ qz_window setDelegate:
slouken@501
   648
            [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ];
slouken@501
   649
    }
slouken@501
   650
    /* We already have a window, just change its size */
slouken@501
   651
    else {
slouken@501
   652
    
slouken@501
   653
        [ qz_window setContentSize:contentRect.size ];
slouken@501
   654
        current->flags |= (SDL_NOFRAME|SDL_RESIZABLE) & mode_flags;
slouken@501
   655
    }
slouken@390
   656
slouken@501
   657
    /* For OpenGL, we bind the context to a subview */
slouken@47
   658
    if ( flags & SDL_OPENGL ) {
slouken@390
   659
slouken@47
   660
        if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
slouken@47
   661
            return NULL;
slouken@47
   662
        }
slouken@390
   663
slouken@501
   664
        window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
slouken@501
   665
        [ window_view setAutoresizingMask: NSViewMinYMargin ];
slouken@501
   666
        [ [ qz_window contentView ] addSubview:window_view ];
slouken@501
   667
        [ gl_context setView: window_view ];
slouken@501
   668
        [ window_view release ];
slouken@47
   669
        [ gl_context makeCurrentContext];
slouken@158
   670
        [ qz_window makeKeyAndOrderFront:nil ];
slouken@47
   671
        current->flags |= SDL_OPENGL;
slouken@47
   672
    }
slouken@501
   673
    /* For 2D, we set the subview to an NSQuickDrawView */
slouken@47
   674
    else {
slouken@390
   675
slouken@501
   676
        /* Only recreate the view if it doesn't already exist */
slouken@501
   677
        if (window_view == nil) {
slouken@501
   678
        
slouken@501
   679
            window_view = [ [ SDL_QuartzWindowView alloc ] initWithFrame:contentRect ];
slouken@501
   680
            [ window_view setAutoresizingMask: NSViewMinYMargin ];
slouken@501
   681
            [ [ qz_window contentView ] addSubview:window_view ];
slouken@501
   682
            [ window_view release ];
slouken@501
   683
            [ qz_window makeKeyAndOrderFront:nil ];
slouken@501
   684
        }
slouken@501
   685
        
slouken@272
   686
        LockPortBits ( [ window_view qdPort ] );
slouken@272
   687
        current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) );
slouken@272
   688
        current->pitch  = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) );
slouken@498
   689
        UnlockPortBits ( [ window_view qdPort ] );
slouken@501
   690
slouken@47
   691
        current->flags |= SDL_SWSURFACE;
slouken@47
   692
        current->flags |= SDL_PREALLOC;
slouken@498
   693
        current->flags |= SDL_ASYNCBLIT;
slouken@498
   694
        
slouken@501
   695
        /* Offset below the title bar to fill the full content region */
slouken@501
   696
        current->pixels += ((int)([ qz_window frame ].size.height) - height) * current->pitch;
slouken@47
   697
slouken@498
   698
        this->UpdateRects     = QZ_UpdateRects;
slouken@498
   699
        this->LockHWSurface   = QZ_LockWindow;
slouken@498
   700
        this->UnlockHWSurface = QZ_UnlockWindow;
slouken@47
   701
    }
slouken@390
   702
slouken@272
   703
    /* Save flags to ensure correct teardown */
slouken@272
   704
    mode_flags = current->flags;
slouken@390
   705
slouken@47
   706
    return current;
slouken@47
   707
}
slouken@47
   708
slouken@390
   709
static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
slouken@390
   710
                                     int height, int bpp, Uint32 flags) {
slouken@47
   711
slouken@47
   712
    current->flags = 0;
slouken@390
   713
slouken@47
   714
    /* Setup full screen video */
slouken@47
   715
    if ( flags & SDL_FULLSCREEN ) {
slouken@47
   716
        current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags );
slouken@47
   717
        if (current == NULL)
slouken@47
   718
            return NULL;
slouken@47
   719
    }
slouken@47
   720
    /* Setup windowed video */
slouken@47
   721
    else {
slouken@47
   722
        /* Force bpp to the device's bpp */
slouken@272
   723
        bpp = device_bpp;
slouken@47
   724
        current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags);
slouken@47
   725
        if (current == NULL)
slouken@47
   726
            return NULL;
slouken@47
   727
    }
slouken@390
   728
slouken@47
   729
    /* Setup the new pixel format */
slouken@47
   730
    {
slouken@390
   731
        int amask = 0,
slouken@390
   732
        rmask = 0,
slouken@390
   733
        gmask = 0,
slouken@390
   734
        bmask = 0;
slouken@390
   735
slouken@47
   736
        switch (bpp) {
slouken@47
   737
            case 16:   /* (1)-5-5-5 RGB */
slouken@390
   738
                amask = 0;
slouken@58
   739
                rmask = 0x7C00;
slouken@58
   740
                gmask = 0x03E0;
slouken@58
   741
                bmask = 0x001F;
slouken@47
   742
                break;
slouken@47
   743
            case 24:
slouken@47
   744
                SDL_SetError ("24bpp is not available");
slouken@47
   745
                return NULL;
slouken@47
   746
            case 32:   /* (8)-8-8-8 ARGB */
slouken@155
   747
                amask = 0x00000000;
slouken@47
   748
                rmask = 0x00FF0000;
slouken@47
   749
                gmask = 0x0000FF00;
slouken@47
   750
                bmask = 0x000000FF;
slouken@47
   751
                break;
slouken@47
   752
        }
slouken@390
   753
slouken@47
   754
        if ( ! SDL_ReallocFormat (current, bpp,
slouken@47
   755
                                  rmask, gmask, bmask, amask ) ) {
slouken@390
   756
            SDL_SetError ("Couldn't reallocate pixel format");
slouken@390
   757
            return NULL;
slouken@390
   758
           }
slouken@47
   759
    }
slouken@390
   760
slouken@272
   761
    /* Signal successful completion (used internally) */
slouken@155
   762
    video_set = SDL_TRUE;
slouken@390
   763
slouken@47
   764
    return current;
slouken@47
   765
}
slouken@47
   766
slouken@390
   767
static int QZ_ToggleFullScreen (_THIS, int on) {
slouken@576
   768
    return 0;
slouken@47
   769
}
slouken@47
   770
slouken@390
   771
static int QZ_SetColors (_THIS, int first_color, int num_colors,
slouken@390
   772
                         SDL_Color *colors) {
slouken@47
   773
slouken@47
   774
    CGTableCount  index;
slouken@47
   775
    CGDeviceColor color;
slouken@390
   776
slouken@47
   777
    for (index = first_color; index < first_color+num_colors; index++) {
slouken@390
   778
slouken@47
   779
        /* Clamp colors between 0.0 and 1.0 */
slouken@47
   780
        color.red   = colors->r / 255.0;
slouken@47
   781
        color.blue  = colors->b / 255.0;
slouken@47
   782
        color.green = colors->g / 255.0;
slouken@390
   783
slouken@47
   784
        colors++;
slouken@390
   785
slouken@47
   786
        CGPaletteSetColorAtIndex (palette, color, index);
slouken@47
   787
    }
slouken@390
   788
slouken@47
   789
    if ( CGDisplayNoErr != CGDisplaySetPalette (display_id, palette) )
slouken@47
   790
        return 0;
slouken@390
   791
slouken@47
   792
    return 1;
slouken@47
   793
}
slouken@47
   794
slouken@588
   795
static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface) {
slouken@588
   796
slouken@588
   797
    return 1;
slouken@588
   798
}
slouken@588
   799
slouken@588
   800
static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface) {
slouken@588
   801
slouken@588
   802
}
slouken@588
   803
slouken@588
   804
 /* The VBL delay is based on code by Ian R Ollmann's RezLib <iano@cco.caltech.edu> */
slouken@588
   805
 static AbsoluteTime QZ_SecondsToAbsolute ( double seconds ) {
slouken@588
   806
    
slouken@588
   807
    union
slouken@588
   808
    {
slouken@588
   809
        UInt64	i;
slouken@588
   810
        Nanoseconds ns;
slouken@588
   811
    } temp;
slouken@588
   812
        
slouken@588
   813
    temp.i = seconds * 1000000000.0;
slouken@588
   814
    
slouken@588
   815
    return NanosecondsToAbsolute ( temp.ns );
slouken@588
   816
}
slouken@588
   817
slouken@588
   818
static int QZ_ThreadFlip (_THIS) {
slouken@588
   819
slouken@588
   820
    Uint8 *src, *dst;
slouken@588
   821
    int skip, len, h;
slouken@588
   822
    
slouken@588
   823
    /*
slouken@588
   824
        Give this thread the highest scheduling priority possible,
slouken@588
   825
        in the hopes that it will immediately run after the VBL delay
slouken@588
   826
    */
slouken@588
   827
    {
slouken@588
   828
        pthread_t current_thread;
slouken@588
   829
        int policy;
slouken@588
   830
        struct sched_param param;
slouken@588
   831
        
slouken@588
   832
        current_thread = pthread_self ();
slouken@588
   833
        pthread_getschedparam (current_thread, &policy, &param);
slouken@588
   834
        policy = SCHED_RR;
slouken@588
   835
        param.sched_priority = sched_get_priority_max (policy);
slouken@588
   836
        pthread_setschedparam (current_thread, policy, &param);
slouken@588
   837
    }
slouken@588
   838
    
slouken@588
   839
    while (1) {
slouken@588
   840
    
slouken@588
   841
        SDL_SemWait (sem1);
slouken@588
   842
        if (quit_thread)
slouken@588
   843
            return 0;
slouken@588
   844
                
slouken@588
   845
        dst = CGDisplayBaseAddress (display_id);
slouken@588
   846
        src = current_buffer;
slouken@588
   847
        len = SDL_VideoSurface->w * SDL_VideoSurface->format->BytesPerPixel;
slouken@588
   848
        h = SDL_VideoSurface->h;
slouken@588
   849
        skip = SDL_VideoSurface->pitch;
slouken@588
   850
    
slouken@588
   851
        /* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
slouken@588
   852
        {
slouken@588
   853
            
slouken@588
   854
            /* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
slouken@588
   855
            double refreshRate;
slouken@588
   856
            double linesPerSecond;
slouken@588
   857
            double target;
slouken@588
   858
            double position;
slouken@588
   859
            double adjustment;
slouken@588
   860
            AbsoluteTime nextTime;        
slouken@588
   861
            CFNumberRef refreshRateCFNumber;
slouken@588
   862
            
slouken@588
   863
            refreshRateCFNumber = CFDictionaryGetValue (mode, kCGDisplayRefreshRate);
slouken@588
   864
            if ( NULL == refreshRateCFNumber ) {
slouken@588
   865
                SDL_SetError ("Mode has no refresh rate");
slouken@588
   866
                goto ERROR;
slouken@588
   867
            }
slouken@588
   868
            
slouken@588
   869
            if ( 0 == CFNumberGetValue (refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) ) {
slouken@588
   870
                SDL_SetError ("Error getting refresh rate");
slouken@588
   871
                goto ERROR;
slouken@588
   872
            }
slouken@588
   873
            
slouken@588
   874
            if ( 0 == refreshRate ) {
slouken@588
   875
               
slouken@588
   876
               SDL_SetError ("Display has no refresh rate, using 60hz");
slouken@588
   877
                
slouken@588
   878
                /* ok, for LCD's we'll emulate a 60hz refresh, which may or may not look right */
slouken@588
   879
                refreshRate = 60.0;
slouken@588
   880
            }
slouken@588
   881
            
slouken@588
   882
            linesPerSecond = refreshRate * h;
slouken@588
   883
            target = h;
slouken@588
   884
        
slouken@588
   885
            /* Figure out the first delay so we start off about right */
slouken@588
   886
            position = CGDisplayBeamPosition (display_id);
slouken@588
   887
            if (position > target)
slouken@588
   888
                position = 0;
slouken@588
   889
            
slouken@588
   890
            adjustment = (target - position) / linesPerSecond; 
slouken@588
   891
            
slouken@588
   892
            nextTime = AddAbsoluteToAbsolute (UpTime (), QZ_SecondsToAbsolute (adjustment));
slouken@588
   893
        
slouken@588
   894
            MPDelayUntil (&nextTime);
slouken@588
   895
        }
slouken@588
   896
        
slouken@588
   897
        
slouken@588
   898
        /* On error, skip VBL delay */
slouken@588
   899
        ERROR:
slouken@588
   900
        
slouken@588
   901
        while ( h-- ) {
slouken@588
   902
        
slouken@588
   903
            memcpy (dst, src, len);
slouken@588
   904
            src += skip;
slouken@588
   905
            dst += skip;
slouken@588
   906
        }
slouken@588
   907
        
slouken@588
   908
        /* signal flip completion */
slouken@588
   909
        SDL_SemPost (sem2);
slouken@588
   910
    }
slouken@588
   911
    
slouken@588
   912
    return 0;
slouken@588
   913
}
slouken@588
   914
        
slouken@588
   915
static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface) {
slouken@588
   916
slouken@588
   917
    /* wait for previous flip to complete */
slouken@588
   918
    SDL_SemWait (sem2);
slouken@588
   919
    
slouken@588
   920
    current_buffer = surface->pixels;
slouken@588
   921
        
slouken@588
   922
    if (surface->pixels == sw_buffers[0])
slouken@588
   923
        surface->pixels = sw_buffers[1];
slouken@588
   924
    else
slouken@588
   925
        surface->pixels = sw_buffers[0];
slouken@588
   926
    
slouken@588
   927
    /* signal worker thread to do the flip */
slouken@588
   928
    SDL_SemPost (sem1);
slouken@588
   929
    
slouken@588
   930
    return 0;
slouken@588
   931
}
slouken@588
   932
slouken@588
   933
slouken@588
   934
static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects) {
slouken@588
   935
slouken@588
   936
    /* perform a flip if someone calls updaterects on a doublebuferred surface */
slouken@588
   937
    this->FlipHWSurface (this, SDL_VideoSurface);
slouken@588
   938
}
slouken@588
   939
slouken@47
   940
static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) {
slouken@390
   941
#pragma unused(this,num_rects,rects)
slouken@47
   942
}
slouken@47
   943
slouken@501
   944
/*
slouken@501
   945
    The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com,
slouken@501
   946
    who supplied sample code for Carbon.
slouken@501
   947
*/
slouken@272
   948
static int QZ_IsWindowObscured (NSWindow *window) {
slouken@272
   949
slouken@390
   950
    //#define TEST_OBSCURED 1
slouken@272
   951
slouken@272
   952
#if TEST_OBSCURED
slouken@390
   953
slouken@501
   954
    /*  
slouken@501
   955
        In order to determine if a direct copy to the screen is possible,
slouken@390
   956
        we must figure out if there are any windows covering ours (including shadows).
slouken@390
   957
        This can be done by querying the window server about the on screen
slouken@390
   958
        windows for their screen rectangle and window level.
slouken@390
   959
        The procedure used below is puts accuracy before speed; however, it aims to call
slouken@390
   960
        the window server the fewest number of times possible to keep things reasonable.
slouken@390
   961
        In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW
slouken@272
   962
    
slouken@390
   963
    Notes:
slouken@390
   964
        -Calls into the Window Server involve IPC which is slow.
slouken@390
   965
        -Getting a rectangle seems slower than getting the window level
slouken@390
   966
        -The window list we get back is in sorted order, top to bottom
slouken@390
   967
        -On average, I suspect, most windows above ours are dock icon windows (hence optimization)
slouken@390
   968
        -Some windows above ours are always there, and cannot move or obscure us (menu bar)
slouken@390
   969
    
slouken@390
   970
    Bugs:
slouken@390
   971
        -no way (yet) to deactivate direct drawing when a window is dragged,
slouken@390
   972
        or suddenly obscured, so drawing continues and can produce garbage
slouken@390
   973
        We need some kind of locking mechanism on window movement to prevent this
slouken@390
   974
    
slouken@390
   975
        -deactivated normal windows use activated normal
slouken@390
   976
        window shadows (slight inaccuraccy)
slouken@272
   977
    */
slouken@390
   978
slouken@272
   979
    /* Cache the connection to the window server */
slouken@390
   980
    static CGSConnectionID    cgsConnection = (CGSConnectionID) -1;
slouken@390
   981
slouken@272
   982
    /* Cache the dock icon windows */
slouken@272
   983
    static CGSWindowID          dockIcons[kMaxWindows];
slouken@272
   984
    static int                  numCachedDockIcons = 0;
slouken@390
   985
slouken@390
   986
    CGSWindowID                windows[kMaxWindows];
slouken@390
   987
    CGSWindowCount             i, count;
slouken@390
   988
    CGSWindowLevel             winLevel;
slouken@390
   989
    CGSRect                    winRect;
slouken@272
   990
slouken@272
   991
    CGSRect contentRect;
slouken@272
   992
    int     windowNumber;
slouken@272
   993
    //int     isMainWindow;
slouken@390
   994
    int     firstDockIcon;
slouken@272
   995
    int     dockIconCacheMiss;
slouken@272
   996
    int     windowContentOffset;
slouken@390
   997
slouken@272
   998
    int     obscured = SDL_TRUE;
slouken@390
   999
slouken@272
  1000
    if ( [ window isVisible ] ) {
slouken@390
  1001
slouken@501
  1002
        /*  
slouken@501
  1003
            walk the window list looking for windows over top of
slouken@501
  1004
            (or casting a shadow on) ours 
slouken@501
  1005
        */
slouken@390
  1006
slouken@501
  1007
        /* 
slouken@501
  1008
           Get a connection to the window server
slouken@501
  1009
           Should probably be moved out into SetVideoMode() or InitVideo()
slouken@501
  1010
        */
slouken@272
  1011
        if (cgsConnection == (CGSConnectionID) -1) {
slouken@272
  1012
            cgsConnection = (CGSConnectionID) 0;
slouken@272
  1013
            cgsConnection = _CGSDefaultConnection ();
slouken@272
  1014
        }
slouken@390
  1015
slouken@390
  1016
        if (cgsConnection) {
slouken@390
  1017
slouken@272
  1018
            if ( ! [ window styleMask ] & NSBorderlessWindowMask )
slouken@272
  1019
                windowContentOffset = 22;
slouken@272
  1020
            else
slouken@272
  1021
                windowContentOffset = 0;
slouken@390
  1022
slouken@272
  1023
            windowNumber = [ window windowNumber ];
slouken@272
  1024
            //isMainWindow = [ window isMainWindow ];
slouken@390
  1025
slouken@272
  1026
            /* The window list is sorted according to order on the screen */
slouken@272
  1027
            count = 0;
slouken@272
  1028
            CGSGetOnScreenWindowList (cgsConnection, 0, kMaxWindows, windows, &count);
slouken@272
  1029
            CGSGetScreenRectForWindow (cgsConnection, windowNumber, &contentRect);
slouken@390
  1030
slouken@272
  1031
            /* adjust rect for window title bar (if present) */
slouken@272
  1032
            contentRect.origin.y    += windowContentOffset;
slouken@272
  1033
            contentRect.size.height -= windowContentOffset;
slouken@390
  1034
slouken@272
  1035
            firstDockIcon = -1;
slouken@272
  1036
            dockIconCacheMiss = SDL_FALSE;
slouken@390
  1037
slouken@501
  1038
            /* 
slouken@501
  1039
                The first window is always an empty window with level kCGSWindowLevelTop
slouken@501
  1040
                so start at index 1
slouken@501
  1041
            */
slouken@272
  1042
            for (i = 1; i < count; i++) {
slouken@390
  1043
slouken@272
  1044
                /* If we reach our window in the list, it cannot be obscured */
slouken@272
  1045
                if (windows[i] == windowNumber) {
slouken@390
  1046
slouken@272
  1047
                    obscured = SDL_FALSE;
slouken@272
  1048
                    break;
slouken@272
  1049
                }
slouken@272
  1050
                else {
slouken@390
  1051
slouken@272
  1052
                    float shadowSide;
slouken@272
  1053
                    float shadowTop;
slouken@272
  1054
                    float shadowBottom;
slouken@272
  1055
slouken@272
  1056
                    CGSGetWindowLevel (cgsConnection, windows[i], &winLevel);
slouken@390
  1057
slouken@272
  1058
                    if (winLevel == kCGSWindowLevelDockIcon) {
slouken@390
  1059
slouken@272
  1060
                        int j;
slouken@390
  1061
slouken@272
  1062
                        if (firstDockIcon < 0) {
slouken@390
  1063
slouken@272
  1064
                            firstDockIcon = i;
slouken@390
  1065
slouken@272
  1066
                            if (numCachedDockIcons > 0) {
slouken@390
  1067
slouken@272
  1068
                                for (j = 0; j < numCachedDockIcons; j++) {
slouken@390
  1069
slouken@272
  1070
                                    if (windows[i] == dockIcons[j])
slouken@272
  1071
                                        i++;
slouken@272
  1072
                                    else
slouken@272
  1073
                                        break;
slouken@272
  1074
                                }
slouken@390
  1075
slouken@272
  1076
                                if (j != 0) {
slouken@390
  1077
slouken@272
  1078
                                    i--;
slouken@390
  1079
slouken@272
  1080
                                    if (j < numCachedDockIcons) {
slouken@390
  1081
slouken@272
  1082
                                        dockIconCacheMiss = SDL_TRUE;
slouken@272
  1083
                                    }
slouken@272
  1084
                                }
slouken@272
  1085
slouken@272
  1086
                            }
slouken@272
  1087
                        }
slouken@390
  1088
slouken@272
  1089
                        continue;
slouken@272
  1090
                    }
slouken@272
  1091
                    else if (winLevel == kCGSWindowLevelMenuIgnore
slouken@272
  1092
                             /* winLevel == kCGSWindowLevelTop */) {
slouken@390
  1093
slouken@272
  1094
                        continue; /* cannot obscure window */
slouken@272
  1095
                    }
slouken@272
  1096
                    else if (winLevel == kCGSWindowLevelDockMenu ||
slouken@272
  1097
                             winLevel == kCGSWindowLevelMenu) {
slouken@390
  1098
slouken@272
  1099
                        shadowSide = 18;
slouken@272
  1100
                        shadowTop = 4;
slouken@390
  1101
                        shadowBottom = 22;
slouken@272
  1102
                    }
slouken@272
  1103
                    else if (winLevel == kCGSWindowLevelUtility) {
slouken@390
  1104
slouken@272
  1105
                        shadowSide = 8;
slouken@272
  1106
                        shadowTop = 4;
slouken@272
  1107
                        shadowBottom = 12;
slouken@272
  1108
                    }
slouken@272
  1109
                    else if (winLevel == kCGSWindowLevelNormal) {
slouken@390
  1110
slouken@501
  1111
                        /* 
slouken@501
  1112
                            These numbers are for foreground windows,
slouken@501
  1113
                            they are too big (but will work) for background windows 
slouken@501
  1114
                        */
slouken@272
  1115
                        shadowSide = 20;
slouken@272
  1116
                        shadowTop = 10;
slouken@272
  1117
                        shadowBottom = 24;
slouken@272
  1118
                    }
slouken@272
  1119
                    else if (winLevel == kCGSWindowLevelDock) {
slouken@390
  1120
slouken@272
  1121
                        /* Create dock icon cache */
slouken@272
  1122
                        if (numCachedDockIcons != (i-firstDockIcon) ||
slouken@272
  1123
                            dockIconCacheMiss) {
slouken@390
  1124
slouken@272
  1125
                            numCachedDockIcons = i - firstDockIcon;
slouken@390
  1126
                            memcpy (dockIcons, &(windows[firstDockIcon]),
slouken@272
  1127
                                    numCachedDockIcons * sizeof(*windows));
slouken@272
  1128
                        }
slouken@390
  1129
slouken@272
  1130
                        /* no shadow */
slouken@272
  1131
                        shadowSide = 0;
slouken@272
  1132
                        shadowTop = 0;
slouken@272
  1133
                        shadowBottom = 0;
slouken@272
  1134
                    }
slouken@272
  1135
                    else {
slouken@390
  1136
slouken@501
  1137
                        /*
slouken@501
  1138
                            kCGSWindowLevelDockLabel,
slouken@501
  1139
                            kCGSWindowLevelDock,
slouken@501
  1140
                            kOther???
slouken@501
  1141
                        */
slouken@390
  1142
slouken@272
  1143
                        /* no shadow */
slouken@272
  1144
                        shadowSide = 0;
slouken@272
  1145
                        shadowTop = 0;
slouken@272
  1146
                        shadowBottom = 0;
slouken@272
  1147
                    }
slouken@390
  1148
slouken@272
  1149
                    CGSGetScreenRectForWindow (cgsConnection, windows[i], &winRect);
slouken@390
  1150
slouken@272
  1151
                    winRect.origin.x -= shadowSide;
slouken@272
  1152
                    winRect.origin.y -= shadowTop;
slouken@272
  1153
                    winRect.size.width += shadowSide;
slouken@272
  1154
                    winRect.size.height += shadowBottom;
slouken@390
  1155
slouken@272
  1156
                    if (NSIntersectsRect (contentRect, winRect)) {
slouken@390
  1157
slouken@272
  1158
                        obscured = SDL_TRUE;
slouken@272
  1159
                        break;
slouken@272
  1160
                    }
slouken@390
  1161
slouken@390
  1162
                } /* window was not our window */
slouken@390
  1163
slouken@272
  1164
            } /* iterate over windows */
slouken@390
  1165
slouken@272
  1166
        } /* get cgsConnection */
slouken@390
  1167
slouken@272
  1168
    } /* window is visible */
slouken@272
  1169
    
slouken@272
  1170
    return obscured;
slouken@272
  1171
#else
slouken@272
  1172
    return SDL_TRUE;
slouken@272
  1173
#endif
slouken@272
  1174
}
slouken@272
  1175
slouken@501
  1176
slouken@498
  1177
/* Locking functions for the software window buffer */
slouken@498
  1178
static int QZ_LockWindow (_THIS, SDL_Surface *surface) {
slouken@498
  1179
    
slouken@498
  1180
    return LockPortBits ( [ window_view qdPort ] );
slouken@498
  1181
}
slouken@498
  1182
slouken@498
  1183
static void QZ_UnlockWindow (_THIS, SDL_Surface *surface) {
slouken@498
  1184
slouken@498
  1185
    UnlockPortBits ( [ window_view qdPort ] );
slouken@498
  1186
}
slouken@498
  1187
slouken@390
  1188
static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) {
slouken@272
  1189
slouken@47
  1190
    if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) {
slouken@47
  1191
        QZ_GL_SwapBuffers (this);
slouken@47
  1192
    }
slouken@501
  1193
    else if ( [ qz_window isMiniaturized ] ) {
slouken@501
  1194
    
slouken@501
  1195
        /* Do nothing if miniaturized */
slouken@272
  1196
    }
slouken@501
  1197
    
slouken@272
  1198
    else if ( ! QZ_IsWindowObscured (qz_window) ) {
slouken@390
  1199
slouken@272
  1200
        /* Use direct copy to flush contents to the display */
slouken@272
  1201
        CGrafPtr savePort;
slouken@272
  1202
        CGrafPtr dstPort, srcPort;
slouken@272
  1203
        const BitMap  *dstBits, *srcBits;
slouken@390
  1204
        Rect     dstRect, srcRect;
slouken@272
  1205
        Point    offset;
slouken@272
  1206
        int i;
slouken@390
  1207
slouken@272
  1208
        GetPort (&savePort);
slouken@390
  1209
slouken@272
  1210
        dstPort = CreateNewPortForCGDisplayID ((UInt32)display_id);
slouken@272
  1211
        srcPort = [ window_view qdPort ];
slouken@390
  1212
slouken@272
  1213
        offset.h = 0;
slouken@272
  1214
        offset.v = 0;
slouken@272
  1215
        SetPort (srcPort);
slouken@272
  1216
        LocalToGlobal (&offset);
slouken@390
  1217
slouken@272
  1218
        SetPort (dstPort);
slouken@390
  1219
slouken@272
  1220
        LockPortBits (dstPort);
slouken@272
  1221
        LockPortBits (srcPort);
slouken@390
  1222
slouken@272
  1223
        dstBits = GetPortBitMapForCopyBits (dstPort);
slouken@272
  1224
        srcBits = GetPortBitMapForCopyBits (srcPort);
slouken@390
  1225
slouken@272
  1226
        for (i = 0; i < numRects; i++) {
slouken@390
  1227
slouken@272
  1228
            SetRect (&srcRect, rects[i].x, rects[i].y,
slouken@272
  1229
                     rects[i].x + rects[i].w,
slouken@272
  1230
                     rects[i].y + rects[i].h);
slouken@390
  1231
slouken@272
  1232
            SetRect (&dstRect,
slouken@390
  1233
                     rects[i].x + offset.h,
slouken@272
  1234
                     rects[i].y + offset.v,
slouken@272
  1235
                     rects[i].x + rects[i].w + offset.h,
slouken@272
  1236
                     rects[i].y + rects[i].h + offset.v);
slouken@390
  1237
slouken@272
  1238
            CopyBits (srcBits, dstBits,
slouken@272
  1239
                      &srcRect, &dstRect, srcCopy, NULL);
slouken@390
  1240
slouken@272
  1241
        }
slouken@390
  1242
slouken@272
  1243
        SetPort (savePort);
slouken@272
  1244
    }
slouken@47
  1245
    else {
slouken@272
  1246
        /* Use QDFlushPortBuffer() to flush content to display */
slouken@47
  1247
        int i;
slouken@47
  1248
        RgnHandle dirty = NewRgn ();
slouken@47
  1249
        RgnHandle temp  = NewRgn ();
slouken@390
  1250
slouken@47
  1251
        SetEmptyRgn (dirty);
slouken@390
  1252
slouken@47
  1253
        /* Build the region of dirty rectangles */
slouken@47
  1254
        for (i = 0; i < numRects; i++) {
slouken@390
  1255
slouken@390
  1256
            MacSetRectRgn (temp, rects[i].x, rects[i].y,
slouken@501
  1257
                        rects[i].x + rects[i].w, rects[i].y + rects[i].h);
slouken@47
  1258
            MacUnionRgn (dirty, temp, dirty);
slouken@47
  1259
        }
slouken@390
  1260
slouken@501
  1261
        QZ_DrawResizeIcon (this, dirty);
slouken@501
  1262
        
slouken@47
  1263
        /* Flush the dirty region */
slouken@272
  1264
        QDFlushPortBuffer ( [ window_view qdPort ], dirty );
slouken@47
  1265
        DisposeRgn (dirty);
slouken@47
  1266
        DisposeRgn (temp);
slouken@47
  1267
    }
slouken@47
  1268
}
slouken@47
  1269
slouken@47
  1270
static void QZ_VideoQuit (_THIS) {
slouken@47
  1271
icculus@560
  1272
    /* Restore gamma settings */
icculus@560
  1273
    CGDisplayRestoreColorSyncSettings ();
icculus@560
  1274
icculus@560
  1275
    /* Ensure the cursor will be visible and working when we quit */
icculus@560
  1276
    CGDisplayShowCursor (display_id);
icculus@560
  1277
    CGAssociateMouseAndMouseCursorPosition (1);
icculus@560
  1278
    
slouken@47
  1279
    QZ_UnsetVideoMode (this);
slouken@47
  1280
    CGPaletteRelease (palette);
slouken@47
  1281
}
slouken@47
  1282
slouken@47
  1283
static int  QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) {
slouken@47
  1284
slouken@47
  1285
    CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
slouken@272
  1286
slouken@47
  1287
    return 0;
slouken@47
  1288
}
slouken@47
  1289
slouken@390
  1290
static int  QZ_LockHWSurface(_THIS, SDL_Surface *surface) {
slouken@47
  1291
slouken@47
  1292
    return 1;
slouken@47
  1293
}
slouken@47
  1294
slouken@272
  1295
static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) {
slouken@272
  1296
slouken@47
  1297
}
slouken@47
  1298
slouken@47
  1299
static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) {
slouken@47
  1300
}
slouken@47
  1301
slouken@47
  1302
/*
slouken@390
  1303
 int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) {
slouken@390
  1304
     return 0;
slouken@390
  1305
 }
slouken@390
  1306
 */
slouken@47
  1307
slouken@47
  1308
/* Gamma functions */
slouken@47
  1309
static int QZ_SetGamma (_THIS, float red, float green, float blue) {
slouken@47
  1310
slouken@47
  1311
    const CGGammaValue min = 0.0, max = 1.0;
slouken@272
  1312
slouken@272
  1313
    if (red == 0.0)
slouken@272
  1314
        red = FLT_MAX;
slouken@272
  1315
    else
slouken@272
  1316
        red = 1.0 / red;
slouken@272
  1317
slouken@272
  1318
    if (green == 0.0)
slouken@272
  1319
        green = FLT_MAX;
slouken@272
  1320
    else
slouken@272
  1321
        green = 1.0 / green;
slouken@272
  1322
slouken@272
  1323
    if (blue == 0.0)
slouken@272
  1324
        blue = FLT_MAX;
slouken@272
  1325
    else
slouken@272
  1326
        blue  = 1.0 / blue;
slouken@390
  1327
slouken@390
  1328
    if ( CGDisplayNoErr == CGSetDisplayTransferByFormula
slouken@390
  1329
         (display_id, min, max, red, min, max, green, min, max, blue) ) {
slouken@390
  1330
slouken@272
  1331
        return 0;
slouken@272
  1332
    }
slouken@272
  1333
    else {
slouken@390
  1334
slouken@47
  1335
        return -1;
slouken@272
  1336
    }
slouken@47
  1337
}
slouken@47
  1338
slouken@47
  1339
static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) {
slouken@47
  1340
slouken@47
  1341
    CGGammaValue dummy;
slouken@272
  1342
    if ( CGDisplayNoErr == CGGetDisplayTransferByFormula
slouken@390
  1343
         (display_id, &dummy, &dummy, red,
slouken@390
  1344
          &dummy, &dummy, green, &dummy, &dummy, blue) )
slouken@390
  1345
slouken@272
  1346
        return 0;
slouken@272
  1347
    else
slouken@47
  1348
        return -1;
slouken@47
  1349
}
slouken@47
  1350
slouken@47
  1351
static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) {
slouken@390
  1352
slouken@390
  1353
    const CGTableCount tableSize = 255;
slouken@390
  1354
    CGGammaValue redTable[tableSize];
slouken@390
  1355
    CGGammaValue greenTable[tableSize];
slouken@390
  1356
    CGGammaValue blueTable[tableSize];
slouken@390
  1357
slouken@390
  1358
    int i;
slouken@390
  1359
slouken@390
  1360
    /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
slouken@390
  1361
    for (i = 0; i < 256; i++)
slouken@390
  1362
        redTable[i % 256] = ramp[i] / 65535.0;
slouken@390
  1363
slouken@390
  1364
    for (i=256; i < 512; i++)
slouken@390
  1365
        greenTable[i % 256] = ramp[i] / 65535.0;
slouken@390
  1366
slouken@390
  1367
    for (i=512; i < 768; i++)
slouken@390
  1368
        blueTable[i % 256] = ramp[i] / 65535.0;
slouken@390
  1369
slouken@390
  1370
    if ( CGDisplayNoErr == CGSetDisplayTransferByTable
slouken@390
  1371
         (display_id, tableSize, redTable, greenTable, blueTable) )
slouken@272
  1372
        return 0;
slouken@272
  1373
    else
slouken@47
  1374
        return -1;
slouken@47
  1375
}
slouken@47
  1376
slouken@47
  1377
static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) {
slouken@390
  1378
slouken@47
  1379
    const CGTableCount tableSize = 255;
slouken@47
  1380
    CGGammaValue redTable[tableSize];
slouken@47
  1381
    CGGammaValue greenTable[tableSize];
slouken@47
  1382
    CGGammaValue blueTable[tableSize];
slouken@47
  1383
    CGTableCount actual;
slouken@47
  1384
    int i;
slouken@390
  1385
slouken@390
  1386
    if ( CGDisplayNoErr != CGGetDisplayTransferByTable
slouken@390
  1387
         (display_id, tableSize, redTable, greenTable, blueTable, &actual) ||
slouken@390
  1388
         actual != tableSize)
slouken@390
  1389
slouken@47
  1390
        return -1;
slouken@390
  1391
slouken@47
  1392
    /* Pack tables into one array, with values from 0 to 65535 */
slouken@47
  1393
    for (i = 0; i < 256; i++)
slouken@47
  1394
        ramp[i] = redTable[i % 256] * 65535.0;
slouken@390
  1395
slouken@47
  1396
    for (i=256; i < 512; i++)
slouken@47
  1397
        ramp[i] = greenTable[i % 256] * 65535.0;
slouken@390
  1398
slouken@47
  1399
    for (i=512; i < 768; i++)
slouken@47
  1400
        ramp[i] = blueTable[i % 256] * 65535.0;
slouken@390
  1401
slouken@390
  1402
    return 0;
slouken@47
  1403
}
slouken@47
  1404
slouken@272
  1405
/* OpenGL helper functions (used internally) */
slouken@272
  1406
slouken@47
  1407
static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) {
slouken@47
  1408
slouken@47
  1409
    NSOpenGLPixelFormatAttribute attr[32];
slouken@47
  1410
    NSOpenGLPixelFormat *fmt;
slouken@47
  1411
    int i = 0;
slouken@47
  1412
    int colorBits = bpp;
slouken@47
  1413
slouken@47
  1414
    if ( flags & SDL_FULLSCREEN ) {
slouken@390
  1415
slouken@47
  1416
        attr[i++] = NSOpenGLPFAFullScreen;
slouken@47
  1417
    }
slouken@47
  1418
    /* In windowed mode, the OpenGL pixel depth must match device pixel depth */
slouken@390
  1419
    else if ( colorBits != device_bpp ) {
slouken@47
  1420
slouken@47
  1421
        colorBits = device_bpp;
slouken@47
  1422
    }
slouken@390
  1423
slouken@47
  1424
    attr[i++] = NSOpenGLPFAColorSize;
slouken@47
  1425
    attr[i++] = colorBits;
slouken@390
  1426
slouken@47
  1427
    attr[i++] = NSOpenGLPFADepthSize;
slouken@47
  1428
    attr[i++] = this->gl_config.depth_size;
slouken@47
  1429
slouken@47
  1430
    if ( this->gl_config.double_buffer ) {
slouken@47
  1431
        attr[i++] = NSOpenGLPFADoubleBuffer;
slouken@47
  1432
    }
slouken@390
  1433
slouken@450
  1434
    if ( this->gl_config.stereo ) {
slouken@450
  1435
        attr[i++] = NSOpenGLPFAStereo;
slouken@450
  1436
    }
slouken@450
  1437
slouken@47
  1438
    if ( this->gl_config.stencil_size != 0 ) {
slouken@47
  1439
        attr[i++] = NSOpenGLPFAStencilSize;
slouken@47
  1440
        attr[i++] = this->gl_config.stencil_size;
slouken@47
  1441
    }
slouken@390
  1442
slouken@656
  1443
    if ( this->gl_config.multisamplebuffers != 0 ) {
slouken@656
  1444
        attr[i++] = NSOpenGLPFASampleBuffers;
slouken@656
  1445
        attr[i++] = this->gl_config.multisamplebuffers;
slouken@656
  1446
    }
slouken@656
  1447
slouken@656
  1448
    if ( this->gl_config.multisamplesamples != 0 ) {
slouken@656
  1449
        attr[i++] = NSOpenGLPFASamples;
slouken@656
  1450
        attr[i++] = this->gl_config.multisamplesamples;
slouken@656
  1451
    }
slouken@656
  1452
slouken@47
  1453
    attr[i++] = NSOpenGLPFAScreenMask;
slouken@47
  1454
    attr[i++] = CGDisplayIDToOpenGLDisplayMask (display_id);
slouken@47
  1455
    attr[i] = 0;
slouken@390
  1456
slouken@47
  1457
    fmt = [ [ NSOpenGLPixelFormat alloc ] initWithAttributes:attr ];
slouken@47
  1458
    if (fmt == nil) {
slouken@47
  1459
        SDL_SetError ("Failed creating OpenGL pixel format");
slouken@47
  1460
        return 0;
slouken@47
  1461
    }
slouken@390
  1462
slouken@390
  1463
    gl_context = [ [ NSOpenGLContext alloc ] initWithFormat:fmt
slouken@390
  1464
                                               shareContext:nil];
slouken@390
  1465
slouken@47
  1466
    if (gl_context == nil) {
slouken@47
  1467
        SDL_SetError ("Failed creating OpenGL context");
slouken@47
  1468
        return 0;
slouken@390
  1469
    }
slouken@390
  1470
slouken@668
  1471
    /*
slouken@668
  1472
     * Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
slouken@668
  1473
     *  "You are blowing a couple of the internal OpenGL function caches. This
slouken@668
  1474
     *  appears to be happening in the VAO case.  You can tell OpenGL to up
slouken@668
  1475
     *  the cache size by issuing the following calls right after you create
slouken@668
  1476
     *  the OpenGL context.  The default cache size is 16."    --ryan.
slouken@668
  1477
     */
slouken@668
  1478
slouken@668
  1479
    #ifndef GLI_ARRAY_FUNC_CACHE_MAX
slouken@668
  1480
    #define GLI_ARRAY_FUNC_CACHE_MAX 284
slouken@668
  1481
    #endif
slouken@668
  1482
slouken@668
  1483
    #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
slouken@668
  1484
    #define GLI_SUBMIT_FUNC_CACHE_MAX 280
slouken@668
  1485
    #endif
slouken@668
  1486
slouken@668
  1487
    {
slouken@668
  1488
        long cache_max = 64;
slouken@668
  1489
        CGLContextObj ctx = [ gl_context cglContext ];
slouken@668
  1490
        CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
slouken@668
  1491
        CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
slouken@668
  1492
    }
slouken@668
  1493
slouken@668
  1494
    /* End Wisdom from Apple Engineer section. --ryan. */
slouken@668
  1495
slouken@47
  1496
    /* Convince SDL that the GL "driver" is loaded */
slouken@47
  1497
    this->gl_config.driver_loaded = 1;
slouken@390
  1498
slouken@47
  1499
    [ fmt release ];
slouken@390
  1500
slouken@47
  1501
    return 1;
slouken@47
  1502
}
slouken@47
  1503
slouken@47
  1504
static void QZ_TearDownOpenGL (_THIS) {
slouken@47
  1505
slouken@47
  1506
    [ NSOpenGLContext clearCurrentContext ];
slouken@47
  1507
    [ gl_context clearDrawable ];
slouken@47
  1508
    [ gl_context release ];
slouken@47
  1509
}
slouken@47
  1510
slouken@272
  1511
slouken@47
  1512
/* SDL OpenGL functions */
slouken@47
  1513
slouken@47
  1514
static int    QZ_GL_LoadLibrary    (_THIS, const char *location) {
slouken@197
  1515
    this->gl_config.driver_loaded = 1;
slouken@47
  1516
    return 1;
slouken@47
  1517
}
slouken@47
  1518
slouken@47
  1519
static void*  QZ_GL_GetProcAddress (_THIS, const char *proc) {
slouken@47
  1520
slouken@47
  1521
    /* We may want to cache the bundleRef at some point */
slouken@47
  1522
    CFBundleRef bundle;
slouken@390
  1523
    CFURLRef bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault,
slouken@390
  1524
                                                        CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true);
slouken@390
  1525
slouken@390
  1526
    CFStringRef functionName = CFStringCreateWithCString
slouken@47
  1527
        (kCFAllocatorDefault, proc, kCFStringEncodingASCII);
slouken@390
  1528
slouken@47
  1529
    void *function;
slouken@390
  1530
slouken@47
  1531
    bundle = CFBundleCreate (kCFAllocatorDefault, bundleURL);
slouken@47
  1532
    assert (bundle != NULL);
slouken@390
  1533
slouken@47
  1534
    function = CFBundleGetFunctionPointerForName (bundle, functionName);
slouken@47
  1535
slouken@47
  1536
    CFRelease ( bundleURL );
slouken@47
  1537
    CFRelease ( functionName );
slouken@47
  1538
    CFRelease ( bundle );
slouken@390
  1539
slouken@47
  1540
    return function;
slouken@47
  1541
}
slouken@47
  1542
slouken@47
  1543
static int    QZ_GL_GetAttribute   (_THIS, SDL_GLattr attrib, int* value) {
slouken@47
  1544
slouken@347
  1545
    GLenum attr = 0;
slouken@308
  1546
slouken@308
  1547
    QZ_GL_MakeCurrent (this);
slouken@308
  1548
slouken@47
  1549
    switch (attrib) {
slouken@390
  1550
        case SDL_GL_RED_SIZE: attr = GL_RED_BITS;   break;
slouken@390
  1551
        case SDL_GL_BLUE_SIZE: attr = GL_BLUE_BITS;  break;
slouken@390
  1552
        case SDL_GL_GREEN_SIZE: attr = GL_GREEN_BITS; break;
slouken@390
  1553
        case SDL_GL_ALPHA_SIZE: attr = GL_ALPHA_BITS; break;
slouken@390
  1554
        case SDL_GL_DOUBLEBUFFER: attr = GL_DOUBLEBUFFER; break;
slouken@390
  1555
        case SDL_GL_DEPTH_SIZE: attr = GL_DEPTH_BITS;  break;
slouken@390
  1556
        case SDL_GL_STENCIL_SIZE: attr = GL_STENCIL_BITS; break;
slouken@390
  1557
        case SDL_GL_ACCUM_RED_SIZE: attr = GL_ACCUM_RED_BITS; break;
slouken@390
  1558
        case SDL_GL_ACCUM_GREEN_SIZE: attr = GL_ACCUM_GREEN_BITS; break;
slouken@390
  1559
        case SDL_GL_ACCUM_BLUE_SIZE: attr = GL_ACCUM_BLUE_BITS; break;
slouken@390
  1560
        case SDL_GL_ACCUM_ALPHA_SIZE: attr = GL_ACCUM_ALPHA_BITS; break;
slouken@450
  1561
        case SDL_GL_STEREO: attr = GL_STEREO; break;
slouken@656
  1562
        case SDL_GL_MULTISAMPLEBUFFERS: attr = GL_SAMPLE_BUFFERS_ARB; break;
slouken@656
  1563
        case SDL_GL_MULTISAMPLESAMPLES: attr = GL_SAMPLES_ARB; break;
slouken@390
  1564
        case SDL_GL_BUFFER_SIZE:
slouken@308
  1565
        {
slouken@308
  1566
            GLint bits = 0;
slouken@308
  1567
            GLint component;
slouken@308
  1568
slouken@308
  1569
            /* there doesn't seem to be a single flag in OpenGL for this! */
slouken@308
  1570
            glGetIntegerv (GL_RED_BITS, &component);   bits += component;
slouken@308
  1571
            glGetIntegerv (GL_GREEN_BITS,&component);  bits += component;
slouken@308
  1572
            glGetIntegerv (GL_BLUE_BITS, &component);  bits += component;
slouken@308
  1573
            glGetIntegerv (GL_ALPHA_BITS, &component); bits += component;
slouken@308
  1574
slouken@308
  1575
            *value = bits;
slouken@308
  1576
        }
slouken@308
  1577
        return 0;
slouken@47
  1578
    }
slouken@272
  1579
slouken@324
  1580
    glGetIntegerv (attr, (GLint *)value);
slouken@308
  1581
    return 0;
slouken@47
  1582
}
slouken@47
  1583
slouken@47
  1584
static int    QZ_GL_MakeCurrent    (_THIS) {
slouken@47
  1585
    [ gl_context makeCurrentContext ];
slouken@47
  1586
    return 0;
slouken@47
  1587
}
slouken@47
  1588
slouken@47
  1589
static void   QZ_GL_SwapBuffers    (_THIS) {
slouken@47
  1590
    [ gl_context flushBuffer ];
slouken@47
  1591
}
slouken@272
  1592
slouken@390
  1593
static int QZ_LockYUV (_THIS, SDL_Overlay *overlay) {
slouken@272
  1594
slouken@390
  1595
    return 0;
slouken@390
  1596
}
slouken@390
  1597
slouken@390
  1598
static void QZ_UnlockYUV (_THIS, SDL_Overlay *overlay) {
slouken@390
  1599
slouken@390
  1600
    ;
slouken@390
  1601
}
slouken@390
  1602
slouken@390
  1603
static int QZ_DisplayYUV (_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect) {
slouken@390
  1604
slouken@390
  1605
    OSErr err;
slouken@390
  1606
    CodecFlags flags;
slouken@390
  1607
slouken@390
  1608
    if (dstrect->x != 0 || dstrect->y != 0) {
slouken@390
  1609
slouken@390
  1610
        SDL_SetError ("Need a dstrect at (0,0)");
slouken@390
  1611
        return -1;
slouken@390
  1612
    }
slouken@390
  1613
slouken@390
  1614
    if (dstrect->w != yuv_width || dstrect->h != yuv_height) {
slouken@390
  1615
slouken@390
  1616
        Fixed scale_x, scale_y;
slouken@390
  1617
slouken@390
  1618
        scale_x = FixDiv ( Long2Fix (dstrect->w), Long2Fix (overlay->w) );
slouken@390
  1619
        scale_y = FixDiv ( Long2Fix (dstrect->h), Long2Fix (overlay->h) );
slouken@390
  1620
slouken@390
  1621
        SetIdentityMatrix (yuv_matrix);
slouken@390
  1622
        ScaleMatrix (yuv_matrix, scale_x, scale_y, Long2Fix (0), Long2Fix (0));
slouken@390
  1623
slouken@390
  1624
        SetDSequenceMatrix (yuv_seq, yuv_matrix);
slouken@390
  1625
slouken@390
  1626
        yuv_width = dstrect->w;
slouken@390
  1627
        yuv_height = dstrect->h;
slouken@390
  1628
    }
slouken@390
  1629
slouken@390
  1630
    if( ( err = DecompressSequenceFrameS(
slouken@390
  1631
                                         yuv_seq,
slouken@390
  1632
                                         (void*)yuv_pixmap,
slouken@390
  1633
                                         sizeof (PlanarPixmapInfoYUV420),
slouken@390
  1634
                                         codecFlagUseImageBuffer, &flags, nil ) != noErr ) )
slouken@390
  1635
    {
slouken@390
  1636
        SDL_SetError ("DecompressSequenceFrameS failed");
slouken@390
  1637
    }
slouken@390
  1638
slouken@390
  1639
    return err == noErr;
slouken@390
  1640
}
slouken@390
  1641
slouken@390
  1642
static void QZ_FreeHWYUV (_THIS, SDL_Overlay *overlay) {
slouken@390
  1643
slouken@390
  1644
    CDSequenceEnd (yuv_seq);
slouken@390
  1645
    ExitMovies();
slouken@390
  1646
slouken@390
  1647
    free (overlay->hwfuncs);
slouken@390
  1648
    free (overlay->pitches);
slouken@390
  1649
    free (overlay->pixels);
slouken@390
  1650
slouken@390
  1651
    if (SDL_VideoSurface->flags & SDL_FULLSCREEN) {
slouken@390
  1652
        [ qz_window close ];
slouken@390
  1653
        qz_window = nil;
slouken@390
  1654
    }
slouken@390
  1655
slouken@390
  1656
    free (yuv_matrix);
slouken@390
  1657
    DisposeHandle ((Handle)yuv_idh);
slouken@390
  1658
}
slouken@390
  1659
slouken@390
  1660
#include "SDL_yuvfuncs.h"
slouken@390
  1661
slouken@501
  1662
/* check for 16 byte alignment, bail otherwise */
slouken@390
  1663
#define CHECK_ALIGN(x) do { if ((Uint32)x & 15) { SDL_SetError("Alignment error"); return NULL; } } while(0)
slouken@390
  1664
slouken@501
  1665
/* align a byte offset, return how much to add to make it a multiple of 16 */
slouken@390
  1666
#define ALIGN(x) ((16 - (x & 15)) & 15)
slouken@390
  1667
slouken@390
  1668
static SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height,
slouken@390
  1669
                                         Uint32 format, SDL_Surface *display) {
slouken@390
  1670
slouken@390
  1671
    Uint32 codec;
slouken@390
  1672
    OSStatus err;
slouken@390
  1673
    CGrafPtr port;
slouken@390
  1674
    SDL_Overlay *overlay;
slouken@390
  1675
slouken@390
  1676
    if (format == SDL_YV12_OVERLAY ||
slouken@390
  1677
        format == SDL_IYUV_OVERLAY) {
slouken@390
  1678
slouken@390
  1679
        codec = kYUV420CodecType;
slouken@390
  1680
    }
slouken@390
  1681
    else {
slouken@390
  1682
        SDL_SetError ("Hardware: unsupported video format");
slouken@390
  1683
        return NULL;
slouken@390
  1684
    }
slouken@390
  1685
slouken@390
  1686
    yuv_idh = (ImageDescriptionHandle) NewHandleClear (sizeof(ImageDescription));
slouken@390
  1687
    if (yuv_idh == NULL) {
slouken@390
  1688
        SDL_OutOfMemory();
slouken@390
  1689
        return NULL;
slouken@390
  1690
    }
slouken@390
  1691
slouken@390
  1692
    yuv_matrix = (MatrixRecordPtr) malloc (sizeof(MatrixRecord));
slouken@390
  1693
    if (yuv_matrix == NULL) {
slouken@390
  1694
        SDL_OutOfMemory();
slouken@390
  1695
        return NULL;
slouken@390
  1696
    }
slouken@390
  1697
slouken@390
  1698
    if ( EnterMovies() != noErr ) {
slouken@390
  1699
        SDL_SetError ("Could not init QuickTime for YUV playback");
slouken@390
  1700
        return NULL;
slouken@390
  1701
    }
slouken@390
  1702
slouken@390
  1703
    err = FindCodec (codec, bestSpeedCodec, nil, &yuv_codec);
slouken@390
  1704
    if (err != noErr) {
slouken@390
  1705
        SDL_SetError ("Could not find QuickTime codec for format");
slouken@390
  1706
        return NULL;
slouken@390
  1707
    }
slouken@390
  1708
slouken@390
  1709
    if (SDL_VideoSurface->flags & SDL_FULLSCREEN) {
slouken@390
  1710
slouken@501
  1711
        /*
slouken@501
  1712
          Acceleration requires a window to be present.
slouken@501
  1713
          A CGrafPtr that points to the screen isn't good enough
slouken@501
  1714
        */
slouken@390
  1715
        NSRect content = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
slouken@390
  1716
slouken@390
  1717
        qz_window = [ [ SDL_QuartzWindow alloc ]
slouken@390
  1718
                            initWithContentRect:content
slouken@390
  1719
                            styleMask:NSBorderlessWindowMask
slouken@390
  1720
                            backing:NSBackingStoreBuffered defer:NO ];
slouken@390
  1721
slouken@390
  1722
        if (qz_window == nil) {
slouken@390
  1723
            SDL_SetError ("Could not create the Cocoa window");
slouken@390
  1724
            return NULL;
slouken@390
  1725
        }
slouken@390
  1726
slouken@390
  1727
        [ qz_window setContentView:[ [ SDL_QuartzWindowView alloc ] init ] ];
slouken@390
  1728
        [ qz_window setReleasedWhenClosed:YES ];
slouken@390
  1729
        [ qz_window center ];
slouken@390
  1730
        [ qz_window setAcceptsMouseMovedEvents:YES ];
slouken@390
  1731
        [ qz_window setLevel:CGShieldingWindowLevel() ];
slouken@390
  1732
        [ qz_window makeKeyAndOrderFront:nil ];
slouken@390
  1733
slouken@390
  1734
        port = [ [ qz_window contentView ] qdPort ];
slouken@390
  1735
        SetPort (port);
slouken@501
  1736
        
slouken@501
  1737
        /*
slouken@501
  1738
            BUG: would like to remove white flash when window kicks in
slouken@501
  1739
            {
slouken@501
  1740
                Rect r;
slouken@501
  1741
                SetRect (&r, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
slouken@501
  1742
                PaintRect (&r);
slouken@501
  1743
                QDFlushPortBuffer (port, nil);
slouken@501
  1744
            }
slouken@501
  1745
        */
slouken@390
  1746
    }
slouken@390
  1747
    else {
slouken@501
  1748
        port = [ window_view qdPort ];
slouken@390
  1749
        SetPort (port);
slouken@390
  1750
    }
slouken@390
  1751
    
slouken@390
  1752
    SetIdentityMatrix (yuv_matrix);
slouken@390
  1753
    
slouken@390
  1754
    HLock ((Handle)yuv_idh);
slouken@390
  1755
    
slouken@390
  1756
    (**yuv_idh).idSize = sizeof(ImageDescription);
slouken@390
  1757
    (**yuv_idh).cType  = codec;
slouken@390
  1758
    (**yuv_idh).version = 1;
slouken@390
  1759
    (**yuv_idh).revisionLevel = 0;
slouken@390
  1760
    (**yuv_idh).width = width;
slouken@390
  1761
    (**yuv_idh).height = height;
slouken@390
  1762
    (**yuv_idh).hRes = Long2Fix(72);
slouken@390
  1763
    (**yuv_idh).vRes = Long2Fix(72);
slouken@390
  1764
    (**yuv_idh).spatialQuality = codecLosslessQuality;
slouken@390
  1765
    (**yuv_idh).frameCount = 1;
slouken@390
  1766
    (**yuv_idh).clutID = -1;
slouken@390
  1767
    (**yuv_idh).dataSize = 0;
slouken@500
  1768
    (**yuv_idh).depth = 24;
slouken@390
  1769
    
slouken@390
  1770
    HUnlock ((Handle)yuv_idh);
slouken@390
  1771
    
slouken@390
  1772
    err = DecompressSequenceBeginS (
slouken@390
  1773
                                    &yuv_seq,
slouken@390
  1774
                                    yuv_idh,
slouken@390
  1775
                                    NULL,
slouken@390
  1776
                                    0,
slouken@390
  1777
                                    port,
slouken@390
  1778
                                    NULL,
slouken@390
  1779
                                    NULL,
slouken@390
  1780
                                    yuv_matrix,
slouken@390
  1781
                                    0,
slouken@390
  1782
                                    NULL,
slouken@390
  1783
                                    codecFlagUseImageBuffer,
slouken@390
  1784
                                    codecLosslessQuality,
slouken@390
  1785
                                    yuv_codec);
slouken@390
  1786
    
slouken@390
  1787
    if (err != noErr) {
slouken@390
  1788
        SDL_SetError ("Error trying to start YUV codec.");
slouken@390
  1789
        return NULL;
slouken@390
  1790
    }
slouken@390
  1791
    
slouken@390
  1792
    overlay = (SDL_Overlay*) malloc (sizeof(*overlay));
slouken@390
  1793
    if (overlay == NULL) {
slouken@390
  1794
        SDL_OutOfMemory();
slouken@390
  1795
        return NULL;
slouken@390
  1796
    }
slouken@390
  1797
    
slouken@390
  1798
    overlay->format      = format;
slouken@390
  1799
    overlay->w           = width;
slouken@390
  1800
    overlay->h           = height;
slouken@390
  1801
    overlay->planes      = 3;
slouken@390
  1802
    overlay->hw_overlay  = 1;
slouken@390
  1803
    {
slouken@390
  1804
        int      offset;
slouken@390
  1805
        Uint8  **pixels;
slouken@390
  1806
        Uint16  *pitches;
slouken@390
  1807
        int      plane2, plane3;
slouken@390
  1808
slouken@390
  1809
        if (format == SDL_IYUV_OVERLAY) {
slouken@390
  1810
slouken@390
  1811
            plane2 = 1; /* Native codec format */
slouken@390
  1812
            plane3 = 2;
slouken@390
  1813
        }
slouken@390
  1814
        else if (format == SDL_YV12_OVERLAY) {
slouken@390
  1815
slouken@390
  1816
            /* switch the U and V planes */
slouken@390
  1817
            plane2 = 2; /* U plane maps to plane 3 */
slouken@390
  1818
            plane3 = 1; /* V plane maps to plane 2 */
slouken@390
  1819
        }
slouken@390
  1820
        else {
slouken@390
  1821
            SDL_SetError("Unsupported YUV format");
slouken@390
  1822
            return NULL;
slouken@390
  1823
        }
slouken@390
  1824
slouken@390
  1825
        pixels = (Uint8**) malloc (sizeof(*pixels) * 3);
slouken@390
  1826
        pitches = (Uint16*) malloc (sizeof(*pitches) * 3);
slouken@390
  1827
        if (pixels == NULL || pitches == NULL) {
slouken@390
  1828
            SDL_OutOfMemory();
slouken@390
  1829
            return NULL;
slouken@390
  1830
        }
slouken@390
  1831
slouken@390
  1832
        yuv_pixmap = (PlanarPixmapInfoYUV420*)
slouken@390
  1833
            malloc (sizeof(PlanarPixmapInfoYUV420) +
slouken@390
  1834
                    (width * height * 2));
slouken@390
  1835
        if (yuv_pixmap == NULL) {
slouken@390
  1836
            SDL_OutOfMemory ();
slouken@390
  1837
            return NULL;
slouken@390
  1838
        }
slouken@390
  1839
slouken@501
  1840
        /* CHECK_ALIGN(yuv_pixmap); */
slouken@390
  1841
        offset  = sizeof(PlanarPixmapInfoYUV420);
slouken@501
  1842
        /* offset += ALIGN(offset); */
slouken@501
  1843
        /* CHECK_ALIGN(offset); */
slouken@390
  1844
slouken@390
  1845
        pixels[0] = (Uint8*)yuv_pixmap + offset;
slouken@501
  1846
        /* CHECK_ALIGN(pixels[0]); */
slouken@390
  1847
slouken@390
  1848
        pitches[0] = width;
slouken@390
  1849
        yuv_pixmap->componentInfoY.offset = offset;
slouken@390
  1850
        yuv_pixmap->componentInfoY.rowBytes = width;
slouken@390
  1851
slouken@390
  1852
        offset += width * height;
slouken@390
  1853
        pixels[plane2] = (Uint8*)yuv_pixmap + offset;
slouken@390
  1854
        pitches[plane2] = width / 2;
slouken@390
  1855
        yuv_pixmap->componentInfoCb.offset = offset;
slouken@390
  1856
        yuv_pixmap->componentInfoCb.rowBytes = width / 2;
slouken@390
  1857
slouken@390
  1858
        offset += (width * height / 4);
slouken@390
  1859
        pixels[plane3] = (Uint8*)yuv_pixmap + offset;
slouken@390
  1860
        pitches[plane3] = width / 2;
slouken@390
  1861
        yuv_pixmap->componentInfoCr.offset = offset;
slouken@390
  1862
        yuv_pixmap->componentInfoCr.rowBytes = width / 2;
slouken@390
  1863
slouken@390
  1864
        overlay->pixels = pixels;
slouken@390
  1865
        overlay->pitches = pitches;
slouken@390
  1866
    }
slouken@390
  1867
slouken@390
  1868
    overlay->hwfuncs = malloc (sizeof(*overlay->hwfuncs));
slouken@390
  1869
    if (overlay->hwfuncs == NULL) {
slouken@390
  1870
        SDL_OutOfMemory();
slouken@390
  1871
        return NULL;
slouken@390
  1872
    }
slouken@390
  1873
    
slouken@390
  1874
    overlay->hwfuncs->Lock    = QZ_LockYUV;
slouken@390
  1875
    overlay->hwfuncs->Unlock  = QZ_UnlockYUV;
slouken@390
  1876
    overlay->hwfuncs->Display = QZ_DisplayYUV;
slouken@390
  1877
    overlay->hwfuncs->FreeHW  = QZ_FreeHWYUV;
slouken@390
  1878
slouken@390
  1879
    yuv_width = overlay->w;
slouken@390
  1880
    yuv_height = overlay->h;
slouken@390
  1881
    
slouken@390
  1882
    return overlay;
slouken@576
  1883
}