view src/video/cybergfx/SDL_cgxvideo.c @ 1977:754847f19490

David Hedbor is no longer maintaining the Qtopia code.
author Sam Lantinga <slouken@libsdl.org>
date Thu, 10 Aug 2006 14:35:42 +0000
parents c121d94672cb
children
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2006 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

/*
 * CGX based SDL video driver implementation by Gabriele Greco
 * gabriele.greco@aruba.it
 */

#include "SDL_endian.h"
#include "SDL_timer.h"
#include "SDL_thread.h"
#include "SDL_video.h"
#include "SDL_mouse.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
#include "SDL_cgxgl_c.h"
#include "SDL_cgxvideo.h"
#include "SDL_cgxwm_c.h"
#include "SDL_amigamouse_c.h"
#include "SDL_amigaevents_c.h"
#include "SDL_cgxmodes_c.h"
#include "SDL_cgximage_c.h"

/* Initialization/Query functions */
static int CGX_VideoInit(_THIS, SDL_PixelFormat * vformat);
static SDL_Surface *CGX_SetVideoMode(_THIS, SDL_Surface * current, int width,
                                     int height, int bpp, Uint32 flags);
static int CGX_ToggleFullScreen(_THIS, int on);
static void CGX_UpdateMouse(_THIS);
static int CGX_SetColors(_THIS, int firstcolor, int ncolors,
                         SDL_Color * colors);
static void CGX_VideoQuit(_THIS);

/* CGX driver bootstrap functions */

struct Library *CyberGfxBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;

int
CGX_SetGamma(_THIS, float red, float green, float blue)
{
    SDL_SetError("Gamma correction not supported");
    return -1;
}

int
CGX_GetGamma(_THIS, float red, float green, float blue)
{
    SDL_SetError("Gamma correction not supported");
    return -1;
}

int
CGX_SetGammaRamp(_THIS, Uint16 * ramp)
{
#if 0
    Int i, ncolors;
    XColor xcmap[256];

    /* See if actually setting the gamma is supported */
    if (SDL_Visual->class != DirectColor) {
        SDL_SetError("Gamma correction not supported on this visual");
        return (-1);
    }

    /* Calculate the appropriate palette for the given gamma ramp */
    ncolors = SDL_Visual->map_entries;
    for (i = 0; i < ncolors; ++i) {
        Uint8 c = (256 * i / ncolors);
        xcmap[i].pixel = SDL_MapRGB(this->screen->format, c, c, c);
        xcmap[i].red = ramp[0 * 256 + c];
        xcmap[i].green = ramp[1 * 256 + c];
        xcmap[i].blue = ramp[2 * 256 + c];
        xcmap[i].flags = (DoRed | DoGreen | DoBlue);
    }
    XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
    XSync(GFX_Display, False);

    return (0);

#else
    SDL_SetError("Gamma correction not supported on this visual");
    return (-1);

#endif
}

static void
DestroyScreen(_THIS)
{
    if (currently_fullscreen) {
        if (this->hidden->dbuffer) {
            extern struct MsgPort *safeport, *dispport;

            this->hidden->dbuffer = 0;

            if (safeport) {
                while (GetMsg(safeport) != NULL);
                DeleteMsgPort(safeport);
            }
            if (dispport) {
                while (GetMsg(dispport) != NULL);
                DeleteMsgPort(dispport);
            }

            this->hidden->SB[0]->sb_DBufInfo->dbi_SafeMessage.
                mn_ReplyPort =
                this->hidden->SB[0]->sb_DBufInfo->dbi_DispMessage.
                mn_ReplyPort = NULL;
            this->hidden->SB[1]->sb_DBufInfo->dbi_SafeMessage.
                mn_ReplyPort =
                this->hidden->SB[1]->sb_DBufInfo->dbi_DispMessage.
                mn_ReplyPort = NULL;

            if (this->hidden->SB[1])
                FreeScreenBuffer(SDL_Display, this->hidden->SB[1]);
            if (this->hidden->SB[0])
                FreeScreenBuffer(SDL_Display, this->hidden->SB[0]);


            this->hidden->SB[0] = this->hidden->SB[1] = NULL;

            if (SDL_RastPort && SDL_RastPort != &SDL_Display->RastPort)
                SDL_free(SDL_RastPort);

            SDL_RastPort = NULL;
        }
        CloseScreen(GFX_Display);
        currently_fullscreen = 0;
    } else if (GFX_Display)
        UnlockPubScreen(NULL, GFX_Display);

    GFX_Display = NULL;
}

static int
CGX_Available(void)
{
    struct Library *l;

    l = OpenLibrary("cybergraphics.library", 0L);

    if (l != NULL) {
        D(bug("CGX video device AVAILABLE\n"));
        CloseLibrary(l);
    }
    D(
         else
         bug("**CGX video device UNAVAILABLE\n"));

    return (l != NULL);
}

static void
CGX_DeleteDevice(SDL_VideoDevice * device)
{
    if (device) {
        if (device->hidden) {
            SDL_free(device->hidden);
        }
        if (device->gl_data) {
            SDL_free(device->gl_data);
        }
        SDL_free(device);
    }
}

static SDL_VideoDevice *
CGX_CreateDevice(int devindex)
{
    SDL_VideoDevice *device;

    /* Initialize all variables that we clean on shutdown */
    device = (SDL_VideoDevice *) SDL_malloc(sizeof(SDL_VideoDevice));
    if (device) {
        SDL_memset(device, 0, (sizeof *device));
        device->hidden = (struct SDL_PrivateVideoData *)
            SDL_malloc((sizeof *device->hidden));
        device->gl_data = (struct SDL_PrivateGLData *)
            SDL_malloc((sizeof *device->gl_data));
    }
    if ((device == NULL) || (device->hidden == NULL) ||
        (device->gl_data == NULL)) {
        D(bug("Unable to create video device!\n"));
        SDL_OutOfMemory();
        CGX_DeleteDevice(device);
        return (0);
    }
    SDL_memset(device->hidden, 0, sizeof(*device->hidden));
    SDL_memset(device->gl_data, 0, sizeof(*device->gl_data));

    /* Set the driver flags */
    device->handles_any_size = 1;

    /* Set the function pointers */
    device->VideoInit = CGX_VideoInit;
    device->ListModes = CGX_ListModes;
    device->SetVideoMode = CGX_SetVideoMode;
    device->ToggleFullScreen = CGX_ToggleFullScreen;
    device->UpdateMouse = CGX_UpdateMouse;
    device->SetColors = CGX_SetColors;
    device->UpdateRects = NULL;
    device->VideoQuit = CGX_VideoQuit;
    device->AllocHWSurface = CGX_AllocHWSurface;
    device->CheckHWBlit = CGX_CheckHWBlit;
    device->FillHWRect = CGX_FillHWRect;
    device->SetHWColorKey = CGX_SetHWColorKey;
    device->SetHWAlpha = NULL;
    device->LockHWSurface = CGX_LockHWSurface;
    device->UnlockHWSurface = CGX_UnlockHWSurface;
    device->FlipHWSurface = CGX_FlipHWSurface;
    device->FreeHWSurface = CGX_FreeHWSurface;
    device->SetGamma = CGX_SetGamma;
    device->GetGamma = CGX_GetGamma;
    device->SetGammaRamp = CGX_SetGammaRamp;
    device->GetGammaRamp = NULL;
#if SDL_VIDEO_OPENGL
    device->GL_LoadLibrary = CGX_GL_LoadLibrary;
    device->GL_GetProcAddress = CGX_GL_GetProcAddress;
    device->GL_GetAttribute = CGX_GL_GetAttribute;
    device->GL_MakeCurrent = CGX_GL_MakeCurrent;
    device->GL_SwapBuffers = CGX_GL_SwapBuffers;
#endif
    device->SetIcon = CGX_SetIcon;
    device->SetCaption = CGX_SetCaption;
    device->IconifyWindow = NULL;       /* CGX_IconifyWindow; */
    device->GrabInput = NULL /* CGX_GrabInput */ ;
    device->GetWMInfo = CGX_GetWMInfo;
    device->FreeWMCursor = amiga_FreeWMCursor;
    device->CreateWMCursor = amiga_CreateWMCursor;
    device->ShowWMCursor = amiga_ShowWMCursor;
    device->WarpWMCursor = amiga_WarpWMCursor;
    device->CheckMouseMode = amiga_CheckMouseMode;
    device->InitOSKeymap = amiga_InitOSKeymap;
    device->PumpEvents = amiga_PumpEvents;

    device->free = CGX_DeleteDevice;

    return device;
}

VideoBootStrap CGX_bootstrap = {
    "CGX", "AmigaOS CyberGraphics", CGX_Available, CGX_CreateDevice
};

Uint32
MakeBitMask(_THIS, int type, int format, int *bpp)
{
    D(if (type == 0) bug("REAL pixel format: "));

    if (this->hidden->depth == *bpp) {

        switch (format) {
        case PIXFMT_LUT8:
            D(if (type == 0) bug("LUT8\n"));
            return 0;
        case PIXFMT_BGR15:
        case PIXFMT_RGB15PC:
            switch (type) {
            case 0:
                D(bug("RGB15PC/BGR15\n"));
                return 31;
            case 1:
                return 992;
            case 2:
                return 31744;
            }
        case PIXFMT_RGB15:
        case PIXFMT_BGR15PC:
            switch (type) {
            case 0:
                D(bug("RGB15/BGR15PC\n"));
                return 31744;
            case 1:
                return 992;
            case 2:
                return 31;
            }
        case PIXFMT_BGR16PC:
        case PIXFMT_RGB16:
            switch (type) {
            case 0:
                D(bug("RGB16PC\n"));
                return 63488;
            case 1:
                return 2016;
            case 2:
                return 31;
            }
        case PIXFMT_BGR16:
        case PIXFMT_RGB16PC:
            switch (type) {
            case 0:
                D(bug("RGB16PC/BGR16\n"));
                return 31;
            case 1:
                return 2016;
            case 2:
                return 63488;
            }

        case PIXFMT_RGB24:
            switch (type) {
            case 0:
                D(bug("RGB24/BGR24\n"));
                return 0xff0000;
            case 1:
                return 0xff00;
            case 2:
                return 0xff;
            }
        case PIXFMT_BGR24:
            switch (type) {
            case 0:
                D(bug("BGR24\n"));
                return 0xff;
            case 1:
                return 0xff00;
            case 2:
                return 0xff0000;
            }
        case PIXFMT_ARGB32:
            switch (type) {
            case 0:
                D(bug("ARGB32\n"));
                return 0xff0000;
            case 1:
                return 0xff00;
            case 2:
                return 0xff;
            }
        case PIXFMT_BGRA32:
            switch (type) {
            case 0:
                D(bug("BGRA32\n"));
                return 0xff00;
            case 1:
                return 0xff0000;
            case 2:
                return 0xff000000;
            }
        case PIXFMT_RGBA32:
            switch (type) {
            case 0:
                D(bug("RGBA32\n"));
                return 0xff000000;
            case 1:
                return 0xff0000;
            case 2:
                return 0xff00;
            }
        default:
            D(bug("Unknown pixel format! Default to 24bit\n"));
            return (Uint32) (255 << (type * 8));
        }
    } else {
        D(if (type == 0)
          bug("DIFFERENT from screen.\nAllocated screen format: "));

        switch (*bpp) {
        case 32:
            D(if (type == 0) bug("RGBA32\n"));
            switch (type) {
            case 0:
                return 0xff000000;
            case 1:
                return 0xff0000;
            case 2:
                return 0xff00;
            }
            break;
        case 24:
          use_truecolor:
            switch (type) {
            case 0:
                D(bug("RGB24\n"));
                return 0xff0000;
            case 1:
                return 0xff00;
            case 2:
                return 0xff;
            }
        case 16:
        case 15:
            D(if (type == 0)
              bug("Not supported, switching to 24bit!\n"));
            *bpp = 24;
            goto use_truecolor;
            break;
        default:
            D(if (type == 0) bug("This is a chunky display\n"));
// For chunky display mask is always 0;
            return 0;
        }
    }
    return 0;
}

static int
CGX_VideoInit(_THIS, SDL_PixelFormat * vformat)
{
    int i;
    struct Library *RTGBase;

    D(bug("VideoInit... Opening libraries\n"));

    if (!IntuitionBase) {
        if (!
            (IntuitionBase =
             (struct IntuitionBase *) OpenLibrary("intuition.library",
                                                  39L))) {
            SDL_SetError("Couldn't open intuition V39+");
            return -1;
        }
    }

    if (!GfxBase) {
        if (!
            (GfxBase =
             (struct GfxBase *) OpenLibrary("graphics.library", 39L))) {
            SDL_SetError("Couldn't open graphics V39+");
            return -1;
        }
    }

    if (!CyberGfxBase) {
        if (!(CyberGfxBase = OpenLibrary("cybergraphics.library", 40L))) {
            SDL_SetError("Couldn't open cybergraphics.");
            return (-1);
        }
    }

    if (RTGBase = OpenLibrary("libs:picasso96/rtg.library", 0L)) {
        extern int use_picasso96;

        CloseLibrary(RTGBase);
        use_picasso96 = 1;
    }

    D(bug("Library intialized, locking screen...\n"));

    SDL_Display = LockPubScreen(NULL);

    if (SDL_Display == NULL) {
        D(bug("Cannot lock display...\n"));
        SDL_SetError("Couldn't lock the display");
        return (-1);
    }
    this->info.current_w = SDL_Display->Width;
    this->info.current_h = SDL_Display->Height;

    D(bug("Checking if we are using a CGX native display...\n"));

    if (!IsCyberModeID(GetVPModeID(&SDL_Display->ViewPort))) {
        Uint32 okid =
            BestCModeIDTags(CYBRBIDTG_NominalWidth, SDL_Display->Width,
                            CYBRBIDTG_NominalHeight, SDL_Display->Height,
                            CYBRBIDTG_Depth, 8,
                            TAG_DONE);

        D(bug("Default visual is not CGX native!\n"));

        UnlockPubScreen(NULL, SDL_Display);

        GFX_Display = NULL;

        if (okid != INVALID_ID) {
            GFX_Display = OpenScreenTags(NULL,
                                         SA_Width, SDL_Display->Width,
                                         SA_Height, SDL_Display->Height,
                                         SA_Depth, 8, SA_Quiet, TRUE,
                                         SA_ShowTitle, FALSE,
                                         SA_DisplayID, okid, TAG_DONE);
        }

        if (!GFX_Display) {
            SDL_SetError("Unable to open a suited CGX display");
            return -1;
        } else
            SDL_Display = GFX_Display;

    } else
        GFX_Display = SDL_Display;


    /* See whether or not we need to swap pixels */

    swap_pixels = 0;

// Non e' detto che sia cosi' pero', alcune schede potrebbero gestire i modi in modo differente

    if (SDL_BYTEORDER == SDL_LIL_ENDIAN) {
        swap_pixels = 1;
    }

    D(bug("Before GetVideoModes....\n"));

    /* Get the available video modes */
    if (CGX_GetVideoModes(this) < 0)
        return -1;

    /* Determine the default screen depth:
       Use the default visual (or at least one with the same depth) */

    for (i = 0; i < this->hidden->nvisuals; i++)
        if (this->hidden->visuals[i].depth ==
            GetCyberMapAttr(SDL_Display->RastPort.BitMap, CYBRMATTR_DEPTH))
            break;
    if (i == this->hidden->nvisuals) {
        /* default visual was useless, take the deepest one instead */
        i = 0;
    }
    SDL_Visual = this->hidden->visuals[i].visual;

//      SDL_XColorMap = SDL_DisplayColormap;

    this->hidden->depth = this->hidden->visuals[i].depth;
    D(bug("Init: Setting screen depth to: %ld\n", this->hidden->depth));
    vformat->BitsPerPixel = this->hidden->visuals[i].depth;     /* this->hidden->visuals[i].bpp; */

    {
        int form;
        APTR handle;
        struct DisplayInfo info;

        if (!(handle = FindDisplayInfo(this->hidden->visuals[i].visual))) {
            D(bug("Unable to get visual info...\n"));
            return -1;
        }

        if (!GetDisplayInfoData
            (handle, (char *) &info, sizeof(struct DisplayInfo), DTAG_DISP,
             NULL)) {
            D(bug("Unable to get visual info data...\n"));
            return -1;
        }

        form = GetCyberIDAttr(CYBRIDATTR_PIXFMT, SDL_Visual);

// In this case I use makebitmask in a way that I'm sure I'll get PIXFMT pixel mask

        if (vformat->BitsPerPixel > 8) {
            vformat->Rmask = MakeBitMask(this, 0, form, &this->hidden->depth);
            vformat->Gmask = MakeBitMask(this, 1, form, &this->hidden->depth);
            vformat->Bmask = MakeBitMask(this, 2, form, &this->hidden->depth);
        }
    }

    /* See if we have been passed a window to use */
/*	SDL_windowid = SDL_getenv("SDL_WINDOWID"); */
    SDL_windowid = NULL;

    /* Create the blank cursor */
    SDL_BlankCursor = AllocMem(16, MEMF_CHIP | MEMF_CLEAR);

    /* Fill in some window manager capabilities */
    this->info.wm_available = 1;
    this->info.blit_hw = 1;
    this->info.blit_hw_CC = 1;
    this->info.blit_sw = 1;
    this->info.blit_fill = 1;
    this->info.video_mem = 2000000;     // Not always true but almost any Amiga card has this memory!

    this->hidden->same_format = 0;
    SDL_RastPort = &SDL_Display->RastPort;
    /* We're done! */
    D(bug("End of CGX_VideoInit\n"));

    return (0);
}

void
CGX_DestroyWindow(_THIS, SDL_Surface * screen)
{
    D(bug("Destroy Window...\n"));

    if (!SDL_windowid) {
        /* Hide the managed window */
        int was_fullscreen = 0;

        /* Clean up OpenGL */
        if (screen) {
            screen->flags &= ~SDL_INTERNALOPENGL;
        }

        if (screen && (screen->flags & SDL_FULLSCREEN)) {
            was_fullscreen = 1;
            screen->flags &= ~SDL_FULLSCREEN;
//                      CGX_LeaveFullScreen(this); tolto x crash
        }

        /* Destroy the output window */
        if (SDL_Window) {
            CloseWindow(SDL_Window);
            SDL_Window = NULL;
        }

        /* Free the colormap entries */
        if (SDL_XPixels) {
            int numcolors;
            unsigned long pixel;

            if (this->screen->format && this->hidden->depth == 8
                && !was_fullscreen) {
                numcolors = 1 << this->screen->format->BitsPerPixel;

                if (numcolors > 256)
                    numcolors = 256;

                if (!was_fullscreen && this->hidden->depth == 8) {
                    for (pixel = 0; pixel < numcolors; pixel++) {
                        if (SDL_XPixels[pixel] >= 0)
                            ReleasePen(GFX_Display->ViewPort.
                                       ColorMap, SDL_XPixels[pixel]);
                    }
                }
            }
            SDL_free(SDL_XPixels);
            SDL_XPixels = NULL;
        }
    }
}

static void
CGX_SetSizeHints(_THIS, int w, int h, Uint32 flags)
{
    if (flags & SDL_RESIZABLE) {
        WindowLimits(SDL_Window, 32, 32, 4096, 4096);
    } else {
        WindowLimits(SDL_Window, w, h, w, h);
    }
    if (flags & SDL_FULLSCREEN) {
        flags &= ~SDL_RESIZABLE;
    } else if (SDL_getenv("SDL_VIDEO_CENTERED")) {
        int display_w, display_h;

        display_w = SDL_Display->Width;
        display_h = SDL_Display->Height;
        ChangeWindowBox(SDL_Window,
                        (display_w - w - SDL_Window->BorderLeft -
                         SDL_Window->BorderRight) / 2,
                        (display_h - h - SDL_Window->BorderTop -
                         SDL_Window->BorderBottom) / 2,
                        w + SDL_Window->BorderLeft +
                        SDL_Window->BorderRight,
                        h + SDL_Window->BorderTop + SDL_Window->BorderBottom);
    }
}

int
CGX_CreateWindow(_THIS, SDL_Surface * screen,
                 int w, int h, int bpp, Uint32 flags)
{
#if 0
    int i, depth;
    Uint32 vis;
#endif
    D(bug("CGX_CreateWindow\n"));

    /* If a window is already present, destroy it and start fresh */
    if (SDL_Window) {
        CGX_DestroyWindow(this, screen);
    }

    /* See if we have been given a window id */
    if (SDL_windowid) {
        SDL_Window = (struct Window *) atol(SDL_windowid);
    } else {
        SDL_Window = 0;
    }

    /* find out which visual we are going to use */
#if 0
/* questo l'ho spostato nell'apertura dello schermo, in quanto su Amiga le finestre
   hanno il pixel mode degli schermi.
 */
    /*if ( flags & SDL_INTERNALOPENGL ) {
       SDL_SetError("OpenGL not supported by the Amiga SDL!");
       return -1;
       }
       else { */
    for (i = 0; i < this->hidden->nvisuals; i++) {
        if (this->hidden->visuals[i].depth == bpp)      /* era .depth */
            break;
    }
    if (i == this->hidden->nvisuals) {
        SDL_SetError("No matching visual for requested depth");
        return -1;              /* should never happen */
    }
    vis = this->hidden->visuals[i].visual;
    depth = this->hidden->visuals[i].depth;
//      }
    SDL_Visual = vis;
    this->hidden->depth = depth;
    D(bug("Setting screen depth to: %ld\n", this->hidden->depth));
#endif

    /* Allocate the new pixel format for this video mode */
    {
        Uint32 form;
        APTR handle;
        struct DisplayInfo info;

        if (!(handle = FindDisplayInfo(SDL_Visual)))
            return -1;

        if (!GetDisplayInfoData
            (handle, (char *) &info, sizeof(struct DisplayInfo), DTAG_DISP,
             NULL))
            return -1;

        form = GetCyberIDAttr(CYBRIDATTR_PIXFMT, SDL_Visual);

        if (flags & SDL_HWSURFACE) {
            if (bpp != this->hidden->depth) {
                bpp = this->hidden->depth;
                D(bug("Accel forces bpp to be equal (%ld)\n", bpp));
            }
        }

        D(bug
          ("BEFORE screen allocation: bpp:%ld (real:%ld)\n", bpp,
           this->hidden->depth));

/* With this call if needed I'll revert the wanted bpp to a bpp best suited for the display, actually occurs
   only with requested format 15/16bit and display format != 15/16bit
 */

        if (!SDL_ReallocFormat(screen, bpp,
                               MakeBitMask(this, 0, form, &bpp),
                               MakeBitMask(this, 1, form, &bpp),
                               MakeBitMask(this, 2, form, &bpp), 0))
            return -1;

        D(bug
          ("AFTER screen allocation: bpp:%ld (real:%ld)\n", bpp,
           this->hidden->depth));

    }

    /* Create the appropriate colormap */
/*
	if ( SDL_XColorMap != SDL_DisplayColormap ) {
		XFreeColormap(SDL_Display, SDL_XColorMap);
	}
*/
    if (GetCyberMapAttr(SDL_Display->RastPort.BitMap, CYBRMATTR_PIXFMT) ==
        PIXFMT_LUT8 || bpp == 8) {
        int ncolors, i;
        D(bug("XPixels palette allocation...\n"));

        /* Allocate the pixel flags */

        if (bpp == 8)
            ncolors = 256;
        else
            ncolors = 1 << screen->format->BitsPerPixel;

        SDL_XPixels = (Sint32 *) SDL_malloc(ncolors * sizeof(Sint32));

        if (SDL_XPixels == NULL) {
            SDL_OutOfMemory();
            return -1;
        }


        for (i = 0; i < ncolors; i++)
            SDL_XPixels[i] = -1;

        /* always allocate a private colormap on non-default visuals */
        if (bpp == 8)
            flags |= SDL_HWPALETTE;

        if (flags & SDL_HWPALETTE)
            screen->flags |= SDL_HWPALETTE;
    }

    /* resize the (possibly new) window manager window */

    /* Create (or use) the X11 display window */

    if (!SDL_windowid) {
        if (flags & SDL_FULLSCREEN) {
            SDL_Window = OpenWindowTags(NULL, WA_Width, w, WA_Height, h,
                                        WA_Flags,
                                        WFLG_ACTIVATE | WFLG_RMBTRAP |
                                        WFLG_BORDERLESS | WFLG_BACKDROP |
                                        WFLG_REPORTMOUSE, WA_IDCMP,
                                        IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS
                                        | IDCMP_MOUSEMOVE,
                                        WA_CustomScreen,
                                        (ULONG) SDL_Display, TAG_DONE);

            D(bug
              ("Opening backdrop window %ldx%ld on display %lx!\n", w, h,
               SDL_Display));
        } else {
            /* Create GimmeZeroZero window when OpenGL is used */
            unsigned long gzz = FALSE;
            if (flags & SDL_INTERNALOPENGL) {
                gzz = TRUE;
            }

            SDL_Window =
                OpenWindowTags(NULL, WA_InnerWidth, w, WA_InnerHeight, h,
                               WA_Flags,
                               WFLG_REPORTMOUSE | WFLG_ACTIVATE |
                               WFLG_RMBTRAP | ((flags & SDL_NOFRAME) ? 0
                                               : (WFLG_DEPTHGADGET |
                                                  WFLG_CLOSEGADGET |
                                                  WFLG_DRAGBAR |
                                                  ((flags &
                                                    SDL_RESIZABLE) ?
                                                   WFLG_SIZEGADGET |
                                                   WFLG_SIZEBBOTTOM :
                                                   0))), WA_IDCMP,
                               IDCMP_RAWKEY | IDCMP_CLOSEWINDOW |
                               IDCMP_MOUSEBUTTONS | IDCMP_NEWSIZE |
                               IDCMP_MOUSEMOVE, WA_PubScreen,
                               (ULONG) SDL_Display, WA_GimmeZeroZero,
                               gzz, TAG_DONE);
            D(bug("Opening WB window of size: %ldx%ld!\n", w, h));
        }

        if (!SDL_Window)
            return -1;
    }

    this->hidden->BytesPerPixel =
        GetCyberMapAttr(SDL_Window->RPort->BitMap, CYBRMATTR_BPPIX);

    if (screen->flags & SDL_DOUBLEBUF) {
        if (SDL_RastPort = SDL_malloc(sizeof(struct RastPort))) {
            InitRastPort(SDL_RastPort);
            SDL_RastPort->BitMap = this->hidden->SB[1]->sb_BitMap;
        } else
            return -1;
    } else
        SDL_RastPort = SDL_Window->RPort;

    if (flags & SDL_HWSURFACE)
        screen->flags |= SDL_HWSURFACE;

    if (!SDL_windowid) {
        CGX_SetSizeHints(this, w, h, flags);
    }

    /* Set our colormaps when not setting a GL mode */
/*
	if ( ! (flags & SDL_INTERNALOPENGL) ) {
		XSetWindowColormap(SDL_Display, SDL_Window, SDL_XColorMap);
	}
*/

    /* Map them both and go fullscreen, if requested */
    if (!SDL_windowid) {
        if (flags & SDL_FULLSCREEN) {
            screen->flags |= SDL_FULLSCREEN;
            currently_fullscreen = 1;
//                      CGX_EnterFullScreen(this); Ci siamo gia'!
        } else {
            screen->flags &= ~SDL_FULLSCREEN;
        }
    }
    screen->w = w;
    screen->h = h;
    screen->pitch = SDL_CalculatePitch(screen);
    CGX_ResizeImage(this, screen, flags);

    /* Make OpenGL Context if needed */
    if (flags & SDL_INTERNALOPENGL) {
        if (this->gl_data->gl_active == 0) {
            if (CGX_GL_Init(this) < 0)
                return -1;
            else
                screen->flags |= SDL_INTERNALOPENGL;
        } else {
            if (CGX_GL_Update(this) < 0)
                return -1;
            else
                screen->flags |= SDL_INTERNALOPENGL;
        }
    }
}

int
CGX_ResizeWindow(_THIS, SDL_Surface * screen, int w, int h, Uint32 flags)
{
    D(bug("CGX_ResizeWindow\n"));

    if (!SDL_windowid) {
        /* Resize the window manager window */
        CGX_SetSizeHints(this, w, h, flags);

        ChangeWindowBox(SDL_Window, SDL_Window->LeftEdge,
                        SDL_Window->TopEdge,
                        w + SDL_Window->BorderLeft +
                        SDL_Window->BorderRight,
                        h + SDL_Window->BorderTop + SDL_Window->BorderBottom);

        screen->w = w;
        screen->h = h;
        screen->pitch = SDL_CalculatePitch(screen);
        CGX_ResizeImage(this, screen, flags);
    }
    return (0);
}

static SDL_Surface *
CGX_SetVideoMode(_THIS, SDL_Surface * current,
                 int width, int height, int bpp, Uint32 flags)
{
    Uint32 saved_flags;
    int needcreate = 0;

    D(bug("CGX_SetVideoMode current:%lx\n", current));

    /* Lock the event thread, in multi-threading environments */
    SDL_Lock_EventThread();

// Check if the window needs to be closed or can be resized

    if ((flags & SDL_FULLSCREEN)
        || (current && current->flags & SDL_FULLSCREEN
            && !(flags & SDL_FULLSCREEN)))
        needcreate = 1;

// Check if we need to close an already existing videomode...

    if (current && current->flags & SDL_FULLSCREEN
        && !(flags & SDL_FULLSCREEN)) {
        unsigned long i;
        D(bug("Destroying image, window & screen!\n"));

        CGX_DestroyImage(this, current);
        CGX_DestroyWindow(this, current);
        DestroyScreen(this);
        GFX_Display = SDL_Display = LockPubScreen(NULL);

        bpp = this->hidden->depth =
            GetCyberMapAttr(SDL_Display->RastPort.BitMap, CYBRMATTR_DEPTH);

        for (i = 0; i < this->hidden->nvisuals; i++) {
            if (this->hidden->visuals[i].depth == bpp)  /* era .depth */
                break;
        }
        if (i == this->hidden->nvisuals) {
            SDL_SetError("No matching visual for requested depth");
            return NULL;        /* should never happen */
        }
        SDL_Visual = this->hidden->visuals[i].visual;

        D(bug("Setting screen depth to: %ld\n", this->hidden->depth));

    }
    /* Check the combination of flags we were passed */
    if (flags & SDL_FULLSCREEN) {
        int i;

        /* Clear fullscreen flag if not supported */
        if (SDL_windowid) {
            flags &= ~SDL_FULLSCREEN;
        } else if (current && current->flags & SDL_FULLSCREEN) {
            if (current->w != width ||
                current->h != height ||
                (this->hidden && this->hidden->depth != bpp)) {
                D(bug("Deleting previous window...\n"));
                CGX_DestroyImage(this, current);
                CGX_DestroyWindow(this, current);
                DestroyScreen(this);
                goto buildnewscreen;
            }
        } else
          buildnewscreen:
        {
            Uint32 okid = BestCModeIDTags(CYBRBIDTG_NominalWidth, width,
                                          CYBRBIDTG_NominalHeight,
                                          height,
                                          CYBRBIDTG_Depth, bpp,
                                          TAG_DONE);

            GFX_Display = NULL;

            D(bug("Opening screen...\n"));

            if (okid != INVALID_ID)
                GFX_Display = OpenScreenTags(NULL,
                                             SA_Width, width,
                                             SA_Height, height,
                                             SA_Quiet, TRUE,
                                             SA_ShowTitle, FALSE,
                                             SA_Depth, bpp, SA_DisplayID,
                                             okid, TAG_DONE);

            if (!GFX_Display) {
                GFX_Display = SDL_Display;
                flags &= ~SDL_FULLSCREEN;
                flags &= ~SDL_DOUBLEBUF;
            } else {
                UnlockPubScreen(NULL, SDL_Display);
                SDL_Display = GFX_Display;

                D(bug("Screen opened.\n"));

                if (flags & SDL_DOUBLEBUF) {
                    int ok = 0;
                    D(bug("Start of DBuffering allocations...\n"));

                    if (this->hidden->SB[0] =
                        AllocScreenBuffer(SDL_Display, NULL,
                                          SB_SCREEN_BITMAP)) {

                        if (this->hidden->SB[1] =
                            AllocScreenBuffer(SDL_Display, NULL, 0L)) {
                            extern struct MsgPort *safeport, *dispport;

                            safeport = CreateMsgPort();
                            dispport = CreateMsgPort();

                            if (!safeport || !dispport) {
                                if (safeport) {
                                    DeleteMsgPort(safeport);
                                    safeport = NULL;
                                }
                                if (dispport) {
                                    DeleteMsgPort(dispport);
                                    dispport = NULL;
                                }
                                FreeScreenBuffer(SDL_Display,
                                                 this->hidden->SB[0]);
                                FreeScreenBuffer(SDL_Display,
                                                 this->hidden->SB[1]);
                            } else {
                                extern ULONG safe_sigbit, disp_sigbit;
                                int i;

                                safe_sigbit = 1L << safeport->mp_SigBit;
                                disp_sigbit = 1L << dispport->mp_SigBit;

                                for (i = 0; i < 2; i++) {
                                    this->hidden->SB[i]->
                                        sb_DBufInfo->
                                        dbi_SafeMessage.
                                        mn_ReplyPort = safeport;
                                    this->hidden->SB[i]->
                                        sb_DBufInfo->
                                        dbi_DispMessage.
                                        mn_ReplyPort = dispport;
                                }

                                ok = 1;
                                D(bug("Dbuffering enabled!\n"));
                                this->hidden->dbuffer = 1;
                                current->flags |= SDL_DOUBLEBUF;
                            }
                        } else {
                            FreeScreenBuffer(SDL_Display,
                                             this->hidden->SB[1]);
                            this->hidden->SB[0] = NULL;
                        }
                    }

                    if (!ok)
                        flags &= ~SDL_DOUBLEBUF;
                }
            }

            if (GetCyberMapAttr
                (SDL_Display->RastPort.BitMap, CYBRMATTR_DEPTH) == bpp)
                this->hidden->same_format = 1;
        }

        bpp = this->hidden->depth =
            GetCyberMapAttr(SDL_Display->RastPort.BitMap, CYBRMATTR_DEPTH);
        D(bug("Setting screen depth to: %ld\n", this->hidden->depth));

        for (i = 0; i < this->hidden->nvisuals; i++)
            if (this->hidden->visuals[i].depth == bpp)  /* era .depth */
                break;

        if (i == this->hidden->nvisuals) {
            SDL_SetError("No matching visual for requested depth");
            return NULL;        /* should never happen */
        }
        SDL_Visual = this->hidden->visuals[i].visual;

    }

    /* Set up the X11 window */
    saved_flags = current->flags;

    if (SDL_Window
        && (saved_flags & SDL_INTERNALOPENGL) == (flags & SDL_INTERNALOPENGL)
        && bpp == current->format->BitsPerPixel && !needcreate) {
        if (CGX_ResizeWindow(this, current, width, height, flags) < 0) {
            current = NULL;
            goto done;
        }
    } else {
        if (CGX_CreateWindow(this, current, width, height, bpp, flags) < 0) {
            current = NULL;
            goto done;
        }
    }

#if 0
    /* Set up the new mode framebuffer */
    if (((current->w != width) || (current->h != height)) ||
        ((saved_flags & SDL_INTERNALOPENGL) != (flags & SDL_INTERNALOPENGL)))
    {
        current->w = width;
        current->h = height;
        current->pitch = SDL_CalculatePitch(current);
        CGX_ResizeImage(this, current, flags);
    }
#endif

    current->flags |= (flags & SDL_RESIZABLE);  // Resizable only if the user asked it

  done:
    /* Release the event thread */
    SDL_Unlock_EventThread();

    /* We're done! */
    return (current);
}

static int
CGX_ToggleFullScreen(_THIS, int on)
{
    Uint32 event_thread;

    /* Don't switch if we don't own the window */
    if (SDL_windowid) {
        return (0);
    }

    /* Don't lock if we are the event thread */
    event_thread = SDL_EventThreadID();
    if (event_thread && (SDL_ThreadID() == event_thread)) {
        event_thread = 0;
    }
    if (event_thread) {
        SDL_Lock_EventThread();
    }
    if (on) {
        this->screen->flags |= SDL_FULLSCREEN;
        CGX_EnterFullScreen(this);
    } else {
        this->screen->flags &= ~SDL_FULLSCREEN;
        CGX_LeaveFullScreen(this);
    }

    CGX_RefreshDisplay(this);
    if (event_thread) {
        SDL_Unlock_EventThread();
    }

    SDL_ResetKeyboard();

    return (1);
}

static void
SetSingleColor(Uint32 fmt, unsigned char r, unsigned char g, unsigned char b,
               unsigned char *c)
{
    switch (fmt) {
    case PIXFMT_BGR15:
    case PIXFMT_RGB15PC:
        {
            Uint16 *t = (Uint16 *) c;
            *t = (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10);
        }
        break;
    case PIXFMT_RGB15:
    case PIXFMT_BGR15PC:
        {
            Uint16 *t = (Uint16 *) c;
            *t = (b >> 3) | ((g >> 3) << 5) | ((r >> 3) << 10);
        }
        break;
    case PIXFMT_BGR16PC:
    case PIXFMT_RGB16:
        {
            Uint16 *t = (Uint16 *) c;
            *t = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11);
        }
        break;
    case PIXFMT_BGR16:
    case PIXFMT_RGB16PC:
        {
            Uint16 *t = (Uint16 *) c;
            *t = (r >> 3) | ((g >> 2) << 5) | ((b >> 3) << 11);
        }
        break;
    case PIXFMT_RGB24:
        c[0] = r;
        c[1] = g;
        c[2] = b;
        c[3] = 0;
        break;
    case PIXFMT_BGR24:
        c[0] = b;
        c[1] = g;
        c[2] = r;
        c[3] = 0;
        break;
    case PIXFMT_ARGB32:
        c[0] = 0;
        c[1] = r;
        c[2] = g;
        c[3] = b;
        break;
    case PIXFMT_BGRA32:
        c[0] = b;
        c[1] = g;
        c[2] = r;
        c[3] = 0;
        break;
    case PIXFMT_RGBA32:
        c[0] = r;
        c[1] = g;
        c[2] = b;
        c[3] = 0;
        break;

    default:
        D(bug("Error, SetSingleColor with PIXFMT %ld!\n", fmt));
    }
}

/* Update the current mouse state and position */
static void
CGX_UpdateMouse(_THIS)
{
    /* Lock the event thread, in multi-threading environments */
    SDL_Lock_EventThread();

    if (currently_fullscreen) {
        SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
        SDL_PrivateMouseMotion(0, 0, SDL_Display->MouseX,
                               SDL_Display->MouseY);
    } else {
        if (SDL_Display->MouseX >=
            (SDL_Window->LeftEdge + SDL_Window->BorderLeft)
            && SDL_Display->MouseX <
            (SDL_Window->LeftEdge + SDL_Window->Width -
             SDL_Window->BorderRight)
            && SDL_Display->MouseY >=
            (SDL_Window->TopEdge + SDL_Window->BorderLeft)
            && SDL_Display->MouseY <
            (SDL_Window->TopEdge + SDL_Window->Height -
             SDL_Window->BorderBottom)) {
            SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
            SDL_PrivateMouseMotion(0, 0,
                                   SDL_Display->MouseX -
                                   SDL_Window->LeftEdge -
                                   SDL_Window->BorderLeft,
                                   SDL_Display->MouseY -
                                   SDL_Window->TopEdge -
                                   SDL_Window->BorderTop);
        } else {
            SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
        }
    }
    SDL_Unlock_EventThread();
}

static int
CGX_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
{
    int i;

    /* Check to make sure we have a colormap allocated */

    /* It's easy if we have a hidden colormap */
    if ((this->screen->flags & SDL_HWPALETTE) && currently_fullscreen) {
        ULONG xcmap[256 * 3 + 2];

        xcmap[0] = (ncolors << 16);
        xcmap[0] += firstcolor;

//              D(bug("Setting %ld colors on an HWPALETTE screen\n",ncolors));

        for (i = 0; i < ncolors; i++) {
            xcmap[i * 3 + 1] = colors[i + firstcolor].r << 24;
            xcmap[i * 3 + 2] = colors[i + firstcolor].g << 24;
            xcmap[i * 3 + 3] = colors[i + firstcolor].b << 24;
        }
        xcmap[ncolors * 3 + 1] = 0;
        LoadRGB32(&GFX_Display->ViewPort, xcmap);
    } else {
// XPixels are not needed on 8bit screen with hwpalette
        unsigned long pixel;

        if (SDL_XPixels == NULL) {
            D(bug("SetColors without colormap!"));
            return (0);
        }

        if (this->hidden->depth == 8) {
// In this case I have to unalloc and realloc the full palette
            D(bug("Obtaining %ld colors on the screen\n", ncolors));

            /* Free existing allocated colors */
            for (pixel = 0;
                 pixel < this->screen->format->palette->ncolors; ++pixel) {
                if (SDL_XPixels[pixel] >= 0)
                    ReleasePen(GFX_Display->ViewPort.ColorMap,
                               SDL_XPixels[pixel]);
            }

            /* Try to allocate all the colors */
            for (i = 0; i < this->screen->format->palette->ncolors; ++i) {
                SDL_XPixels[i] =
                    ObtainBestPenA(GFX_Display->ViewPort.ColorMap,
                                   colors[i].r << 24,
                                   colors[i].g << 24,
                                   colors[i].b << 24, NULL);
            }
        } else {
#ifndef USE_CGX_WRITELUTPIXEL
            Uint32 fmt;
            D(bug("Preparing a conversion pixel table...\n"));

            fmt =
                GetCyberMapAttr(SDL_Display->RastPort.BitMap,
                                CYBRMATTR_PIXFMT);

            for (i = 0; i < ncolors; i++) {
                SetSingleColor(fmt, colors[firstcolor + i].r,
                               colors[firstcolor + i].g,
                               colors[firstcolor + i].b, (unsigned char *)
                               &SDL_XPixels[firstcolor + i]);
            }
#else
//                      D(bug("Executing XPixel(%lx) remapping: (from %ld, %ld colors) first: r%ld g%ld b%ld\n",SDL_XPixels,firstcolor,ncolors,colors[firstcolor].r,colors[firstcolor].g,colors[firstcolor].b));
            for (i = 0; i < ncolors; i++)
                SDL_XPixels[i + firstcolor] =
                    (colors[firstcolor + i].r << 16) +
                    (colors[firstcolor + i].g << 8) + colors[firstcolor +
                                                             i].b;
#endif
        }
    }

// Actually it cannot fail!

    return 1;
}

/* Note:  If we are terminated, this could be called in the middle of
   another SDL video routine -- notably UpdateRects.
*/
static void
CGX_VideoQuit(_THIS)
{
    /* Shutdown everything that's still up */
    /* The event thread should be done, so we can touch SDL_Display */
    D(bug("CGX_VideoQuit\n"));

    if (SDL_Display != NULL) {
        /* Clean up OpenGL */
        if (this->gl_data->gl_active == 1) {
            CGX_GL_Quit(this);
        }
        /* Start shutting down the windows */
        D(bug("Destroying image...\n"));
        CGX_DestroyImage(this, this->screen);
        D(bug("Destroying window...\n"));
        CGX_DestroyWindow(this, this->screen);
// Otherwise SDL_VideoQuit will try to free it!
        SDL_VideoSurface = NULL;

        CGX_FreeVideoModes(this);

        /* Free that blank cursor */
        if (SDL_BlankCursor != NULL) {
            FreeMem(SDL_BlankCursor, 16);
            SDL_BlankCursor = NULL;
        }

        /* Close the X11 graphics connection */
        this->hidden->same_format = 0;

        D(bug("Destroying screen...\n"));

        if (GFX_Display != NULL)
            DestroyScreen(this);

        /* Close the X11 display connection */
        SDL_Display = NULL;

        /* Unload GL library after X11 shuts down */
    }

    D(bug("Closing libraries...\n"));

    if (CyberGfxBase) {
        CloseLibrary(CyberGfxBase);
        CyberGfxBase = NULL;
    }

    if (IntuitionBase) {
        CloseLibrary((struct Library *) IntuitionBase);
        IntuitionBase = NULL;
    }
    if (GfxBase) {
        CloseLibrary((struct Library *) GfxBase);
        GfxBase = NULL;
    }

    if (this->screen && (this->screen->flags & SDL_HWSURFACE)) {
        /* Direct screen access, no memory buffer */
        this->screen->pixels = NULL;
    }
    D(bug("End of CGX_VideoQuit.\n"));

}

/* vi: set ts=4 sw=4 expandtab: */