fceux/drivers/pc/sdl-video.cpp

439 lines
9.0 KiB
C++
Raw Normal View History

/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sdl.h"
#include "sdl-opengl.h"
#include "../common/vidblit.h"
#include "sdl-icon.h"
#include "dface.h"
SDL_Surface *screen;
SDL_Surface *BlitBuf; // Used as a buffer when using hardware-accelerated blits.
SDL_Surface *IconSurface=NULL;
static int curbpp;
static int srendline,erendline;
static int tlines;
static int inited=0;
#ifdef OPENGL
extern int sdlhaveogl;
static int usingogl;
static double exs,eys;
#else
static double exs,eys;
#endif
static int eefx;
#define NWIDTH (256-((eoptions&EO_CLIPSIDES)?16:0))
#define NOFFSET (eoptions&EO_CLIPSIDES?8:0)
static int paletterefresh;
/* Return 1 if video was killed, 0 otherwise(video wasn't initialized). */
int KillVideo(void)
{
if(IconSurface)
{
SDL_FreeSurface(IconSurface);
IconSurface=0;
}
if(inited&1)
{
#ifdef OPENGL
if(usingogl)
KillOpenGL();
else
#endif
if(curbpp>8)
KillBlitToHigh();
SDL_QuitSubSystem(SDL_INIT_VIDEO);
inited&=~1;
return(1);
}
inited=0;
return(0);
}
static int sponge;
int InitVideo(FCEUGI *gi)
{
const SDL_VideoInfo *vinf;
int flags=0;
FCEUI_printf("Initializing video...");
FCEUI_GetCurrentVidSystem(&srendline,&erendline);
if(_fullscreen) sponge=Settings.specialfs;
else sponge=Settings.special;
#ifdef OPENGL
usingogl=0;
if(_opengl && sdlhaveogl && !sponge)
{
flags=SDL_OPENGL;
usingogl=1;
}
#endif
#ifdef EXTGUI
GUI_SetVideo(_fullscreen, 0, 0);
#endif
if(!(SDL_WasInit(SDL_INIT_VIDEO)&SDL_INIT_VIDEO))
if(SDL_InitSubSystem(SDL_INIT_VIDEO)==-1)
{
FCEUD_PrintError(SDL_GetError());
return(0);
}
inited|=1;
SDL_ShowCursor(0);
tlines=erendline-srendline+1;
vinf=SDL_GetVideoInfo();
if(vinf->hw_available)
flags|=SDL_HWSURFACE;
if(_fullscreen)
flags|=SDL_FULLSCREEN;
flags|=SDL_HWPALETTE;
//flags|=SDL_DOUBLEBUF;
#ifdef OPENGL
if(usingogl)
{
FCEU_printf("\n Initializing with OpenGL(Use \"-opengl 0\" to disable).\n");
if(_doublebuf)
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
}
else
#endif
if(_doublebuf && (flags&SDL_HWSURFACE))
flags|=SDL_DOUBLEBUF;
if(_fullscreen)
{
int desbpp=_bpp;
exs=_xscalefs;
eys=_yscalefs;
eefx=_efxfs;
#ifdef OPENGL
if(!usingogl) {exs=(int)exs;eys=(int)eys;}
else desbpp=0;
if(sponge)
{
exs=eys=2;
if(sponge == 3 || sponge == 4) exs = eys = 3;
eefx=0;
if(sponge == 1 || sponge == 3) desbpp = 32;
}
if( (usingogl && !_stretchx) || !usingogl)
#endif
if(_xres<NWIDTH*exs || exs <= 0.01)
{
FCEUD_PrintError("xscale out of bounds.");
KillVideo();
return(0);
}
#ifdef OPENGL
if( (usingogl && !_stretchy) || !usingogl)
#endif
if(_yres<tlines*eys || eys <= 0.01)
{
FCEUD_PrintError("yscale out of bounds.");
KillVideo();
return(0);
}
#ifdef EXTGUI
GUI_SetVideo(_fullscreen, _xres, _yres);
#endif
#ifdef OPENGL
if(!(screen = SDL_SetVideoMode(_xres, _yres, desbpp, flags)))
#else
if(!(screen = SDL_SetVideoMode(_xres, _yres, desbpp, flags)))
#endif
{
FCEUD_PrintError(SDL_GetError());
return(0);
}
}
else
{
int desbpp=0;
exs=_xscale;
eys=_yscale;
eefx=_efx;
if(sponge)
{
exs=eys=2;
if(sponge >= 3) exs=eys=3;
eefx=0;
// SDL's 32bpp->16bpp code is slighty faster than mine, at least :/
if(sponge == 1 || sponge == 3) desbpp=32;
}
#ifdef OPENGL
if(!usingogl) {exs=(int)exs;eys=(int)eys;}
if(exs <= 0.01)
{
FCEUD_PrintError("xscale out of bounds.");
KillVideo();
return(0);
}
if(eys <= 0.01)
{
FCEUD_PrintError("yscale out of bounds.");
KillVideo();
return(0);
}
#endif
#ifdef EXTGUI
GUI_SetVideo(_fullscreen, (NWIDTH*exs), tlines*eys);
#endif
screen = SDL_SetVideoMode((int)(NWIDTH*exs), (int)(tlines*eys),
desbpp, flags);
}
curbpp=screen->format->BitsPerPixel;
if(!screen)
{
FCEUD_PrintError(SDL_GetError());
KillVideo();
return(0);
}
//BlitBuf=SDL_CreateRGBSurface(SDL_HWSURFACE,256,240,screen->format->BitsPerPixel,screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,0);
inited=1;
FCEU_printf(" Video Mode: %d x %d x %d bpp %s\n",screen->w,screen->h,screen->format->BitsPerPixel,_fullscreen?"full screen":"");
if(curbpp!=16 && curbpp!=24 && curbpp!=8 && curbpp!=32)
{
FCEU_printf(" Sorry, %dbpp modes are not supported by FCE Ultra. Supported bit depths are 8bpp, 16bpp, and 32bpp.\n",curbpp);
KillVideo();
return(0);
}
if(gi->name)
SDL_WM_SetCaption((const char *)gi->name, (const char *)gi->name);
else
SDL_WM_SetCaption("FCE Ultra","FCE Ultra");
#ifdef LSB_FIRST
IconSurface=SDL_CreateRGBSurfaceFrom((void *)fceu_playicon.pixel_data,32,32,24,32*3,0xFF,0xFF00,0xFF0000,0x00);
#else
IconSurface=SDL_CreateRGBSurfaceFrom((void *)fceu_playicon.pixel_data,32,32,24,32*3,0xFF0000,0xFF00,0xFF,0x00);
#endif
SDL_WM_SetIcon(IconSurface,0);
paletterefresh=1;
if(curbpp>8)
#ifdef OPENGL
if(!usingogl)
#endif
InitBlitToHigh(curbpp>>3,screen->format->Rmask,screen->format->Gmask,screen->format->Bmask,eefx,sponge);
#ifdef OPENGL
if(usingogl)
if(!InitOpenGL((eoptions&EO_CLIPSIDES)?8:0,256-((eoptions&EO_CLIPSIDES)?8:0),srendline,erendline+1,exs,eys,eefx,_openglip,_stretchx,_stretchy,screen))
{
FCEUD_PrintError("Error initializing OpenGL.");
KillVideo();
return(0);
}
#endif
return 1;
}
void ToggleFS(void)
{
extern FCEUGI *CurGame;
KillVideo();
_fullscreen=!_fullscreen;
if(!InitVideo(CurGame))
{
_fullscreen=!_fullscreen;
InitVideo(CurGame);
}
}
static SDL_Color psdl[256];
void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b)
{
psdl[index].r=r;
psdl[index].g=g;
psdl[index].b=b;
paletterefresh=1;
}
void FCEUD_GetPalette(uint8 index, uint8 *r, uint8 *g, uint8 *b)
{
*r=psdl[index].r;
*g=psdl[index].g;
*b=psdl[index].b;
}
static void RedoPalette(void)
{
#ifdef OPENGL
if(usingogl)
SetOpenGLPalette((uint8*)psdl);
else
#endif
{
if(curbpp>8)
SetPaletteBlitToHigh((uint8*)psdl);
else
{
SDL_SetPalette(screen,SDL_PHYSPAL,psdl,0,256);
}
}
}
void LockConsole(){}
void UnlockConsole(){}
void BlitScreen(uint8 *XBuf)
{
SDL_Surface *TmpScreen;
uint8 *dest;
int xo=0,yo=0;
if(!screen) return;
if(paletterefresh)
{
RedoPalette();
paletterefresh=0;
}
#ifdef OPENGL
if(usingogl)
{
BlitOpenGL(XBuf);
return;
}
#endif
XBuf+=srendline*256;
if(BlitBuf) TmpScreen=BlitBuf;
else TmpScreen=screen;
if(SDL_MUSTLOCK(TmpScreen))
if(SDL_LockSurface(TmpScreen))
{
return;
}
dest=(uint8*)TmpScreen->pixels;
if(_fullscreen)
{
xo=(int)(((TmpScreen->w-NWIDTH*exs))/2);
dest+=xo*(curbpp>>3);
if(TmpScreen->h>(tlines*eys))
{
yo=(int)((TmpScreen->h-tlines*eys)/2);
dest+=yo*TmpScreen->pitch;
}
}
if(curbpp>8)
{
if(BlitBuf) {
Blit8ToHigh(XBuf+NOFFSET,dest, NWIDTH, tlines, TmpScreen->pitch,1,1);
} else {
Blit8ToHigh(XBuf+NOFFSET,dest, NWIDTH, tlines, TmpScreen->pitch,
(int)exs,(int)eys);
}
}
else
{
if(BlitBuf) {
Blit8To8(XBuf+NOFFSET,dest, NWIDTH, tlines,
TmpScreen->pitch, 1, 1, 0, sponge);
} else {
Blit8To8(XBuf+NOFFSET, dest, NWIDTH, tlines,
TmpScreen->pitch, (int)exs, (int)eys, eefx, sponge);
}
}
if(SDL_MUSTLOCK(TmpScreen))
SDL_UnlockSurface(TmpScreen);
if(BlitBuf)
{
SDL_Rect srect;
SDL_Rect drect;
srect.x=0;
srect.y=0;
srect.w=NWIDTH;
srect.h=tlines;
drect.x=0;
drect.y=0;
drect.w=(Uint16)(exs*NWIDTH);
drect.h=(Uint16)(eys*tlines);
SDL_BlitSurface(BlitBuf, &srect,screen,&drect);
}
SDL_UpdateRect(screen, xo, yo, (Uint32)(NWIDTH*exs), (Uint32)(tlines*eys));
if(screen->flags&SDL_DOUBLEBUF)
SDL_Flip(screen);
}
uint32 PtoV(uint16 x, uint16 y)
{
y=(uint16)((double)y/eys);
x=(uint16)((double)x/exs);
if(eoptions&EO_CLIPSIDES)
x+=8;
y+=srendline;
return(x|(y<<16));
}