2003-02-16 04:01:45 +00:00
|
|
|
#include "global.h"
|
2002-10-24 03:38:23 +00:00
|
|
|
|
|
|
|
|
#include "SDL.h"
|
|
|
|
|
#include "SDL_utils.h"
|
2004-05-17 01:47:20 +00:00
|
|
|
#include "RageSurface_Load.h"
|
2003-07-22 07:47:27 +00:00
|
|
|
#include "RageFile.h"
|
2003-12-10 05:01:51 +00:00
|
|
|
#include "RageLog.h"
|
2004-06-13 07:11:49 +00:00
|
|
|
#include "RageUtil.h"
|
2004-06-14 00:51:00 +00:00
|
|
|
#include "RageSurface.h"
|
|
|
|
|
#include "RageSurfaceUtils.h"
|
2005-01-20 01:26:15 +00:00
|
|
|
#include "RageSurfaceUtils_Zoom.h"
|
2004-06-14 17:13:46 +00:00
|
|
|
#include "RageThreads.h"
|
2004-06-14 03:11:39 +00:00
|
|
|
#include "StepMania.h"
|
|
|
|
|
|
2004-06-14 02:32:41 +00:00
|
|
|
#include <errno.h>
|
2002-10-24 03:38:23 +00:00
|
|
|
|
2004-03-19 23:14:30 +00:00
|
|
|
bool SDL_GetEvent( SDL_Event &event, int mask )
|
2003-04-12 19:00:56 +00:00
|
|
|
{
|
|
|
|
|
/* SDL_PeepEvents returns error if video isn't initialized. */
|
|
|
|
|
if(!SDL_WasInit(SDL_INIT_VIDEO))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
switch(SDL_PeepEvents(&event, 1, SDL_GETEVENT, mask))
|
|
|
|
|
{
|
|
|
|
|
case 1: return true;
|
|
|
|
|
case 0: return false;
|
2003-04-12 20:23:27 +00:00
|
|
|
default: RageException::Throw("SDL_PeepEvents returned unexpected error: %s", SDL_GetError());
|
2003-04-12 19:00:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
2003-05-26 01:51:59 +00:00
|
|
|
|
2003-05-26 01:43:23 +00:00
|
|
|
/* Reads all currently queued SDL events, clearing them from the queue. */
|
2004-03-19 23:14:30 +00:00
|
|
|
void mySDL_GetAllEvents( vector<SDL_Event> &events )
|
2003-05-26 01:43:23 +00:00
|
|
|
{
|
|
|
|
|
while(1)
|
|
|
|
|
{
|
|
|
|
|
SDL_Event ev;
|
|
|
|
|
if(SDL_PollEvent(&ev) <= 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
events.push_back(ev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pushes the given events onto the SDL event queue. */
|
2004-03-19 23:14:30 +00:00
|
|
|
void mySDL_PushEvents( vector<SDL_Event> &events )
|
2003-05-26 01:43:23 +00:00
|
|
|
{
|
|
|
|
|
for(unsigned i = 0; i < events.size(); ++i)
|
2003-05-26 01:51:59 +00:00
|
|
|
SDL_PushEvent(&events[i]);
|
2003-05-26 01:43:23 +00:00
|
|
|
}
|
2003-04-12 19:00:56 +00:00
|
|
|
|
2003-05-25 23:49:40 +00:00
|
|
|
/* For some bizarre reason, SDL_EventState flushes all events. This is a pain, so
|
|
|
|
|
* avoid it. */
|
2004-06-14 00:51:00 +00:00
|
|
|
uint8_t mySDL_EventState( uint8_t type, int state )
|
2003-05-25 23:49:40 +00:00
|
|
|
{
|
|
|
|
|
if(state == SDL_QUERY)
|
|
|
|
|
return SDL_EventState(type, state);
|
|
|
|
|
|
|
|
|
|
vector<SDL_Event> events;
|
2003-05-26 01:43:23 +00:00
|
|
|
mySDL_GetAllEvents(events);
|
2003-05-25 23:49:40 +00:00
|
|
|
|
2003-05-26 01:43:23 +00:00
|
|
|
/* Set the event mask. */
|
2004-06-14 00:51:00 +00:00
|
|
|
uint8_t ret = SDL_EventState(type, state);
|
2003-05-25 23:49:40 +00:00
|
|
|
|
2003-05-26 01:43:23 +00:00
|
|
|
/* Don't readding events that we just turned off; they'll just sit around
|
|
|
|
|
* in the buffer. */
|
|
|
|
|
for(unsigned i = 0; i < events.size(); )
|
|
|
|
|
{
|
|
|
|
|
if(state == SDL_IGNORE && events[i].type == type)
|
|
|
|
|
events.erase(events.begin()+i);
|
|
|
|
|
else
|
|
|
|
|
i++;
|
2003-05-25 23:49:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Put them back. */
|
2003-05-26 01:43:23 +00:00
|
|
|
mySDL_PushEvents(events);
|
2003-05-25 23:49:40 +00:00
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2003-04-12 19:00:56 +00:00
|
|
|
|
2003-06-04 20:08:51 +00:00
|
|
|
|
2004-04-09 21:52:50 +00:00
|
|
|
/* SDL sometimes fails to set an error, in which case we get the null string. We
|
|
|
|
|
* sometimes use that as a sentinel return value. This function returns "(none)"
|
|
|
|
|
* if no error is set. */
|
2006-01-22 01:00:06 +00:00
|
|
|
RString mySDL_GetError()
|
2004-04-09 21:52:50 +00:00
|
|
|
{
|
2006-01-22 01:00:06 +00:00
|
|
|
RString error = SDL_GetError();
|
2004-04-09 21:52:50 +00:00
|
|
|
if( error == "" )
|
|
|
|
|
return "(none)"; /* SDL sometimes fails to set an error */
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
|
2006-01-22 01:00:06 +00:00
|
|
|
void mySDL_WM_SetIcon( RString sIconFile )
|
2004-05-17 01:47:20 +00:00
|
|
|
{
|
2005-10-24 10:37:56 +00:00
|
|
|
#if !defined(MACOSX)
|
2004-06-14 00:51:00 +00:00
|
|
|
if( sIconFile.empty() )
|
|
|
|
|
{
|
|
|
|
|
SDL_WM_SetIcon(NULL, NULL);
|
2004-05-17 01:47:20 +00:00
|
|
|
return;
|
2004-06-14 00:51:00 +00:00
|
|
|
}
|
2004-05-17 01:47:20 +00:00
|
|
|
|
2006-01-22 01:00:06 +00:00
|
|
|
RString error;
|
2004-06-14 01:13:31 +00:00
|
|
|
RageSurface *srf = RageSurfaceUtils::LoadFile( sIconFile, error );
|
2004-06-14 00:51:00 +00:00
|
|
|
if( srf == NULL )
|
|
|
|
|
return;
|
2004-05-17 01:47:20 +00:00
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
/* Windows icons are 32x32 and SDL can't resize them for us, which
|
|
|
|
|
* causes mask corruption. (Actually, the above icon *is* 32x32;
|
|
|
|
|
* this is here just in case it changes.) */
|
2004-08-28 09:38:22 +00:00
|
|
|
RageSurfaceUtils::Zoom( srf, 32, 32 );
|
2004-05-17 01:47:20 +00:00
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
SDL_Surface *sdl_srf = SDLSurfaceFromRageSurface( srf );
|
|
|
|
|
delete srf;
|
|
|
|
|
|
|
|
|
|
SDL_SetAlpha( sdl_srf, SDL_SRCALPHA, SDL_ALPHA_OPAQUE );
|
|
|
|
|
SDL_WM_SetIcon( sdl_srf, NULL /* derive from alpha */ );
|
|
|
|
|
SDL_FreeSurface( sdl_srf );
|
|
|
|
|
#endif
|
2004-05-17 01:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
/* Create an SDL surface from a RageSurface. */
|
|
|
|
|
SDL_Surface *SDLSurfaceFromRageSurface( RageSurface *surf )
|
2004-05-17 01:47:20 +00:00
|
|
|
{
|
2004-06-14 00:51:00 +00:00
|
|
|
/* SDL will free the data with free(), so we can't just give it surf->pixels. */
|
|
|
|
|
char *buf = (char *) malloc( surf->pitch * surf->h );
|
|
|
|
|
if( buf == NULL )
|
|
|
|
|
RageException::Throw( "malloc(%i): %s", surf->pitch * surf->h, strerror(errno) );
|
|
|
|
|
memcpy( buf, surf->pixels, surf->pitch * surf->h );
|
|
|
|
|
SDL_Surface *ret = SDL_CreateRGBSurfaceFrom( buf,
|
|
|
|
|
surf->w, surf->h, surf->fmt.BitsPerPixel,
|
|
|
|
|
surf->pitch, surf->fmt.Rmask, surf->fmt.Gmask, surf->fmt.Bmask, surf->fmt.Amask );
|
2004-05-17 01:47:20 +00:00
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
/* Copy the palette. */
|
|
|
|
|
if( surf->format->BytesPerPixel == 1 )
|
2004-05-17 01:47:20 +00:00
|
|
|
{
|
2004-06-14 00:51:00 +00:00
|
|
|
ASSERT( sizeof(RageSurfaceColor) == sizeof(SDL_Color) );
|
2004-06-14 01:13:31 +00:00
|
|
|
SDL_SetPalette( ret, SDL_LOGPAL, (SDL_Color *) surf->fmt.palette->colors, 0, 256 );
|
|
|
|
|
|
|
|
|
|
/* If we have one alpha value, transfer it to the color key. */
|
|
|
|
|
int iKey = -1;
|
|
|
|
|
bool bUsesColorKey = true;
|
|
|
|
|
|
|
|
|
|
for( int i = 0; i < surf->format->palette->ncolors; ++i )
|
|
|
|
|
{
|
|
|
|
|
if( surf->format->palette->colors[i].a == 0xFF )
|
|
|
|
|
continue;
|
|
|
|
|
if( surf->format->palette->colors[i].a != 0 )
|
|
|
|
|
{
|
|
|
|
|
bUsesColorKey = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* a == 0 */
|
|
|
|
|
if( iKey != -1 )
|
|
|
|
|
{
|
|
|
|
|
bUsesColorKey = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
iKey = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( bUsesColorKey && iKey != -1 )
|
|
|
|
|
SDL_SetColorKey( ret, SDL_SRCCOLORKEY, iKey );
|
|
|
|
|
|
|
|
|
|
/* XXX: If we have more than one alpha value, or any alpha values between 1 and
|
|
|
|
|
* 254, it needs to be converted to RGBA. I'm not sure that we ever do that
|
|
|
|
|
* with surfaces passed to SDL, though. */
|
2004-05-17 01:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
return ret;
|
2004-05-17 01:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
RageSurface *RageSurfaceFromSDLSurface( SDL_Surface *surf )
|
2004-05-17 01:47:20 +00:00
|
|
|
{
|
2004-06-14 00:51:00 +00:00
|
|
|
uint8_t *buf = new uint8_t[surf->pitch * surf->h];
|
|
|
|
|
memcpy( buf, surf->pixels, surf->pitch * surf->h );
|
|
|
|
|
RageSurface *ret = CreateSurfaceFrom(
|
|
|
|
|
surf->w, surf->h, surf->format->BitsPerPixel,
|
|
|
|
|
surf->format->Rmask, surf->format->Gmask, surf->format->Bmask, surf->format->Amask,
|
|
|
|
|
buf, surf->pitch );
|
2004-05-17 01:47:20 +00:00
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
/* Copy the palette. */
|
|
|
|
|
if( surf->format->BytesPerPixel == 1 )
|
2004-05-17 01:47:20 +00:00
|
|
|
{
|
2004-06-14 00:51:00 +00:00
|
|
|
ASSERT( sizeof(RageSurfaceColor) == sizeof(SDL_Color) );
|
|
|
|
|
memcpy( ret->fmt.palette->colors, surf->format->palette->colors,
|
|
|
|
|
256 * sizeof(RageSurfaceColor) );
|
2004-05-17 01:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
/* Convert SDL "colorkey" to an alpha palette entry. 's "unused" palette entry is undefined. We use it for alpha, so set it to 255. */
|
|
|
|
|
if( surf->format->BitsPerPixel == 8 )
|
2004-05-17 01:47:20 +00:00
|
|
|
{
|
2004-06-14 00:51:00 +00:00
|
|
|
for( int index = 0; index < ret->fmt.palette->ncolors; ++index )
|
|
|
|
|
ret->fmt.palette->colors[index].a = 0xFF;
|
2004-05-17 01:47:20 +00:00
|
|
|
|
2004-06-14 00:51:00 +00:00
|
|
|
/* If the surface had a color key set, transfer it. */
|
|
|
|
|
if( surf->flags & SDL_SRCCOLORKEY )
|
2004-05-17 01:47:20 +00:00
|
|
|
{
|
2004-06-14 00:51:00 +00:00
|
|
|
ASSERT_M( (int)surf->format->colorkey < surf->format->palette->ncolors, ssprintf("%i",surf->format->colorkey) );
|
|
|
|
|
int ckey = surf->format->colorkey;
|
|
|
|
|
ret->fmt.palette->colors[ ckey ].a = 0;
|
2004-05-17 01:47:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
2004-06-14 00:51:00 +00:00
|
|
|
|
|
|
|
|
return ret;
|
2004-05-17 01:47:20 +00:00
|
|
|
}
|
2004-05-18 07:11:11 +00:00
|
|
|
|
2004-06-14 17:13:46 +00:00
|
|
|
#if defined(UNIX)
|
|
|
|
|
#include "archutils/Unix/EmergencyShutdown.h"
|
|
|
|
|
void EmergencyShutdownSDL()
|
|
|
|
|
{
|
|
|
|
|
/* Only do this if the main thread crashes; trying to shut down from
|
|
|
|
|
* another thread causes crashes (eg. GL may be using TLS). */
|
|
|
|
|
if( !strcmp(RageThread::GetCurThreadName(), "Main thread") && SDL_WasInit(SDL_INIT_VIDEO) )
|
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-06-14 05:18:09 +00:00
|
|
|
void SetupSDL()
|
|
|
|
|
{
|
|
|
|
|
static bool bDone = false;
|
|
|
|
|
if( bDone )
|
|
|
|
|
return;
|
|
|
|
|
bDone = true;
|
|
|
|
|
|
|
|
|
|
/* Start SDL (with no subsystems), to make sure we don't use SDL's error handler. */
|
|
|
|
|
SDL_Init( SDL_INIT_NOPARACHUTE );
|
|
|
|
|
|
|
|
|
|
/* Clean up on exit. */
|
|
|
|
|
atexit( SDL_Quit );
|
2004-06-14 17:13:46 +00:00
|
|
|
|
|
|
|
|
#if defined(UNIX)
|
|
|
|
|
/* Attempt to shut down the window on crash. */
|
|
|
|
|
RegisterEmergencyShutdownCallback( EmergencyShutdownSDL );
|
|
|
|
|
#endif
|
2004-09-16 21:32:14 +00:00
|
|
|
|
|
|
|
|
#if defined(LINUX)
|
|
|
|
|
static bool bSetVideoDriver = false;
|
|
|
|
|
if( !bSetVideoDriver )
|
|
|
|
|
{
|
|
|
|
|
bSetVideoDriver = true;
|
|
|
|
|
|
|
|
|
|
/* Most people don't have this set. SDL has a habit of trying to
|
|
|
|
|
* fall back on other drivers (svgalib, aalib), so set it to "x11". */
|
|
|
|
|
const char *sVideoDriver = getenv("SDL_VIDEODRIVER");
|
|
|
|
|
if( sVideoDriver == NULL || sVideoDriver[0] == 0 )
|
|
|
|
|
{
|
|
|
|
|
static char env[] = "SDL_VIDEODRIVER=x11";
|
|
|
|
|
putenv( env );
|
|
|
|
|
} else if( strcmp( sVideoDriver, "x11" ) )
|
|
|
|
|
LOG->Info( "SDL_VIDEODRIVER has been set to %s", sVideoDriver );
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2004-06-14 05:18:09 +00:00
|
|
|
}
|
2004-06-14 03:32:32 +00:00
|
|
|
|
2004-05-18 07:11:11 +00:00
|
|
|
/*
|
|
|
|
|
* (c) 2002-2004 Glenn Maynard
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|