view src/video/cybergfx/SDL_cgxvideo.c @ 1643:51038e80ae59

More general fix for bug #189 The clipping is done at a higher level, and the low level functions are passed clipped rectangles. Drivers which don't support source clipping have not been changed, so the image will be squished instead of clipped, but at least they will no longer crash when the destination rect was out of bounds.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 17 Apr 2006 06:47:23 +0000
parents 8d9bb0cf2c2a
children 0a53c90a37f9 c121d94672cb
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_OPENGL|SDL_OPENGLBLIT);
		}

		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_OPENGL ) {
		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_OPENGL ) {
					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_OPENGL) ) {
		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_OPENGL) {
		if(this->gl_data->gl_active == 0) {
			if(CGX_GL_Init(this) < 0)
				return -1;
			else
				screen->flags |= SDL_OPENGL;
		}
		else {
			if(CGX_GL_Update(this) < 0)
				return -1;
			else
				screen->flags |= SDL_OPENGL;
		}
	}
}

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_OPENGL) == (flags&SDL_OPENGL)
	    && 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_OPENGL) != (flags&SDL_OPENGL)) ) {
		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"));

}