📄 sdl_video.c
字号:
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_video.c,v 1.4 2002/04/22 21:38:03 wmay Exp $";
#endif
/* The high-level video driver subsystem */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_events.h"
#include "SDL_mutex.h"
#include "SDL_sysvideo.h"
#include "SDL_sysevents.h"
#include "SDL_blit.h"
#include "SDL_pixels_c.h"
#include "SDL_events_c.h"
#include "SDL_cursor_c.h"
/* Available video drivers */
static VideoBootStrap *bootstrap[] = {
#ifdef ENABLE_X11
&X11_bootstrap,
#endif
#ifdef ENABLE_DGA
&DGA_bootstrap,
#endif
#ifdef ENABLE_NANOX
&NX_bootstrap,
#endif
#ifdef ENABLE_FBCON
&FBCON_bootstrap,
#endif
#ifdef ENABLE_DIRECTFB
&DirectFB_bootstrap,
#endif
#ifdef ENABLE_PS2GS
&PS2GS_bootstrap,
#endif
#ifdef ENABLE_GGI
&GGI_bootstrap,
#endif
#ifdef ENABLE_VGL
&VGL_bootstrap,
#endif
#ifdef ENABLE_SVGALIB
&SVGALIB_bootstrap,
#endif
#ifdef ENABLE_AALIB
&AALIB_bootstrap,
#endif
#ifdef ENABLE_DIRECTX
&DIRECTX_bootstrap,
#endif
#ifdef ENABLE_WINDIB
&WINDIB_bootstrap,
#endif
#ifdef ENABLE_BWINDOW
&BWINDOW_bootstrap,
#endif
#ifdef ENABLE_TOOLBOX
&TOOLBOX_bootstrap,
#endif
#ifdef ENABLE_DRAWSPROCKET
&DSp_bootstrap,
#endif
#ifdef ENABLE_QUARTZ
&QZ_bootstrap,
#endif
#ifdef ENABLE_CYBERGRAPHICS
&CGX_bootstrap,
#endif
#ifdef ENABLE_PHOTON
&ph_bootstrap,
#endif
#ifdef ENABLE_EPOC
&EPOC_bootstrap,
#endif
#ifdef ENABLE_DUMMYVIDEO
&DUMMY_bootstrap,
#endif
#ifdef ENABLE_XBIOS
&XBIOS_bootstrap,
#endif
#ifdef ENABLE_GEM
&GEM_bootstrap,
#endif
NULL
};
SDL_VideoDevice *current_video = NULL;
/* Various local functions */
int SDL_VideoInit(const char *driver_name, Uint32 flags);
void SDL_VideoQuit(void);
void SDL_GL_UpdateRectsLock(SDL_VideoDevice* this, int numrects, SDL_Rect* rects);
static SDL_GrabMode SDL_WM_GrabInputOff(void);
#ifdef HAVE_OPENGL
static int lock_count = 0;
#endif
/*
* Initialize the video and event subsystems -- determine native pixel format
*/
int SDL_VideoInit (const char *driver_name, Uint32 flags)
{
SDL_VideoDevice *video;
int index;
int i;
SDL_PixelFormat vformat;
Uint32 video_flags;
/* Toggle the event thread flags, based on OS requirements */
#if defined(MUST_THREAD_EVENTS)
flags |= SDL_INIT_EVENTTHREAD;
#elif defined(CANT_THREAD_EVENTS)
if ( (flags & SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD ) {
SDL_SetError("OS doesn't support threaded events");
return(-1);
}
#endif
/* Check to make sure we don't overwrite 'current_video' */
if ( current_video != NULL ) {
SDL_VideoQuit();
}
/* Select the proper video driver */
index = 0;
video = NULL;
if ( driver_name != NULL ) {
#if 0 /* This will be replaced with a better driver selection API */
if ( strrchr(driver_name, ':') != NULL ) {
index = atoi(strrchr(driver_name, ':')+1);
}
#endif
for ( i=0; bootstrap[i]; ++i ) {
if ( strncmp(bootstrap[i]->name, driver_name,
strlen(bootstrap[i]->name)) == 0 ) {
if ( bootstrap[i]->available() ) {
video = bootstrap[i]->create(index);
break;
}
}
}
} else {
for ( i=0; bootstrap[i]; ++i ) {
if ( bootstrap[i]->available() ) {
video = bootstrap[i]->create(index);
if ( video != NULL ) {
break;
}
}
}
}
if ( video == NULL ) {
SDL_SetError("No available video device");
return(-1);
}
current_video = video;
current_video->name = bootstrap[i]->name;
/* Do some basic variable initialization */
video->screen = NULL;
video->shadow = NULL;
video->visible = NULL;
video->physpal = NULL;
video->gammacols = NULL;
video->gamma = NULL;
video->wm_title = NULL;
video->wm_icon = NULL;
video->offset_x = 0;
video->offset_y = 0;
memset(&video->info, 0, (sizeof video->info));
/* Set some very sane GL defaults */
video->gl_config.driver_loaded = 0;
video->gl_config.dll_handle = NULL;
video->gl_config.red_size = 5;
#if 1 /* This seems to work on more video cards, as a default */
video->gl_config.green_size = 5;
#else
video->gl_config.green_size = 6;
#endif
video->gl_config.blue_size = 5;
video->gl_config.alpha_size = 0;
video->gl_config.buffer_size = 0;
video->gl_config.depth_size = 16;
video->gl_config.stencil_size = 0;
video->gl_config.double_buffer = 1;
video->gl_config.accum_red_size = 0;
video->gl_config.accum_green_size = 0;
video->gl_config.accum_blue_size = 0;
video->gl_config.accum_alpha_size = 0;
/* Initialize the video subsystem */
memset(&vformat, 0, sizeof(vformat));
if ( video->VideoInit(video, &vformat) < 0 ) {
SDL_VideoQuit();
return(-1);
}
/* Create a zero sized video surface of the appropriate format */
video_flags = SDL_SWSURFACE;
SDL_VideoSurface = SDL_CreateRGBSurface(video_flags, 0, 0,
vformat.BitsPerPixel,
vformat.Rmask, vformat.Gmask, vformat.Bmask, 0);
if ( SDL_VideoSurface == NULL ) {
SDL_VideoQuit();
return(-1);
}
SDL_PublicSurface = NULL; /* Until SDL_SetVideoMode() */
#if 0 /* Don't change the current palette - may be used by other programs.
* The application can't do anything with the display surface until
* a video mode has been set anyway. :)
*/
/* If we have a palettized surface, create a default palette */
if ( SDL_VideoSurface->format->palette ) {
SDL_PixelFormat *vf = SDL_VideoSurface->format;
SDL_DitherColors(vf->palette->colors, vf->BitsPerPixel);
video->SetColors(video,
0, vf->palette->ncolors, vf->palette->colors);
}
#endif
video->info.vfmt = SDL_VideoSurface->format;
/* Start the event loop */
if ( SDL_StartEventLoop(flags) < 0 ) {
SDL_VideoQuit();
return(-1);
}
SDL_CursorInit(flags & SDL_INIT_EVENTTHREAD);
/* We're ready to go! */
return(0);
}
char *SDL_VideoDriverName(char *namebuf, int maxlen)
{
if ( current_video != NULL ) {
strncpy(namebuf, current_video->name, maxlen-1);
namebuf[maxlen-1] = '\0';
return(namebuf);
}
return(NULL);
}
/*
* Get the current display surface
*/
SDL_Surface *SDL_GetVideoSurface(void)
{
SDL_Surface *visible;
visible = NULL;
if ( current_video ) {
visible = current_video->visible;
}
return(visible);
}
/*
* Get the current information about the video hardware
*/
const SDL_VideoInfo *SDL_GetVideoInfo(void)
{
const SDL_VideoInfo *info;
info = NULL;
if ( current_video ) {
info = ¤t_video->info;
}
return(info);
}
/*
* Return a pointer to an array of available screen dimensions for the
* given format, sorted largest to smallest. Returns NULL if there are
* no dimensions available for a particular format, or (SDL_Rect **)-1
* if any dimension is okay for the given format. If 'format' is NULL,
* the mode list will be for the format given by SDL_GetVideoInfo()->vfmt
*/
SDL_Rect ** SDL_ListModes (SDL_PixelFormat *format, Uint32 flags)
{
SDL_VideoDevice *video = current_video;
SDL_VideoDevice *this = current_video;
SDL_Rect **modes;
modes = NULL;
if ( SDL_VideoSurface ) {
if ( format == NULL ) {
format = SDL_VideoSurface->format;
}
modes = video->ListModes(this, format, flags);
}
return(modes);
}
/*
* Check to see if a particular video mode is supported.
* It returns 0 if the requested mode is not supported under any bit depth,
* or returns the bits-per-pixel of the closest available mode with the
* given width and height. If this bits-per-pixel is different from the
* one used when setting the video mode, SDL_SetVideoMode() will succeed,
* but will emulate the requested bits-per-pixel with a shadow surface.
*/
static Uint8 SDL_closest_depths[4][8] = {
/* 8 bit closest depth ordering */
{ 0, 8, 16, 15, 32, 24, 0, 0 },
/* 15,16 bit closest depth ordering */
{ 0, 16, 15, 32, 24, 8, 0, 0 },
/* 24 bit closest depth ordering */
{ 0, 24, 32, 16, 15, 8, 0, 0 },
/* 32 bit closest depth ordering */
{ 0, 32, 16, 15, 24, 8, 0, 0 }
};
int SDL_VideoModeOK (int width, int height, int bpp, Uint32 flags)
{
int table, b, i;
int supported;
SDL_PixelFormat format;
SDL_Rect **sizes;
/* Currently 1 and 4 bpp are not supported */
if ( bpp < 8 || bpp > 32 ) {
return(0);
}
if ( (width == 0) || (height == 0) ) {
return(0);
}
/* Search through the list valid of modes */
memset(&format, 0, sizeof(format));
supported = 0;
table = ((bpp+7)/8)-1;
SDL_closest_depths[table][0] = bpp;
SDL_closest_depths[table][7] = 0;
for ( b = 0; !supported && SDL_closest_depths[table][b]; ++b ) {
format.BitsPerPixel = SDL_closest_depths[table][b];
sizes = SDL_ListModes(&format, flags);
if ( sizes == (SDL_Rect **)0 ) {
/* No sizes supported at this bit-depth */
continue;
} else
#ifdef macintosh /* MPW optimization bug? */
if ( (sizes == (SDL_Rect **)0xFFFFFFFF) ||
#else
if ( (sizes == (SDL_Rect **)-1) ||
#endif
current_video->handles_any_size ) {
/* Any size supported at this bit-depth */
supported = 1;
continue;
} else
for ( i=0; sizes[i]; ++i ) {
if ((sizes[i]->w == width) && (sizes[i]->h == height)) {
supported = 1;
break;
}
}
}
if ( supported ) {
--b;
return(SDL_closest_depths[table][b]);
} else {
return(0);
}
}
/*
* Get the closest non-emulated video mode to the one requested
*/
static int SDL_GetVideoMode (int *w, int *h, int *BitsPerPixel, Uint32 flags)
{
int table, b, i;
int supported;
int native_bpp;
SDL_PixelFormat format;
SDL_Rect **sizes;
/* Try the original video mode, get the closest depth */
native_bpp = SDL_VideoModeOK(*w, *h, *BitsPerPixel, flags);
if ( native_bpp == *BitsPerPixel ) {
return(1);
}
if ( native_bpp > 0 ) {
*BitsPerPixel = native_bpp;
return(1);
}
/* No exact size match at any depth, look for closest match */
memset(&format, 0, sizeof(format));
supported = 0;
table = ((*BitsPerPixel+7)/8)-1;
SDL_closest_depths[table][0] = *BitsPerPixel;
SDL_closest_depths[table][7] = SDL_VideoSurface->format->BitsPerPixel;
for ( b = 0; !supported && SDL_closest_depths[table][b]; ++b ) {
format.BitsPerPixel = SDL_closest_depths[table][b];
sizes = SDL_ListModes(&format, flags);
if ( sizes == (SDL_Rect **)0 ) {
/* No sizes supported at this bit-depth */
continue;
}
for ( i=0; sizes[i]; ++i ) {
if ((sizes[i]->w < *w) || (sizes[i]->h < *h)) {
if ( i > 0 ) {
--i;
*w = sizes[i]->w;
*h = sizes[i]->h;
*BitsPerPixel = SDL_closest_depths[table][b];
supported = 1;
} else {
/* Largest mode too small... */;
}
break;
}
}
if ( (i > 0) && ! sizes[i] ) {
/* The smallest mode was larger than requested, OK */
--i;
*w = sizes[i]->w;
*h = sizes[i]->h;
*BitsPerPixel = SDL_closest_depths[table][b];
supported = 1;
}
}
if ( ! supported ) {
SDL_SetError("No video mode large enough for %dx%d", *w, *h);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -