/* Mednafen - Multi-system Emulator
 *
 * 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 "main.h"
#include "video.h"
#include "opengl.h"
#include "nongl.h"

#include "icon.h"
#include "netplay.h"
#include "cheat.h"

#include "scalebit.h"
#include "hqxx-common.h"
#include "nnx.h"
#include "debugger.h"
#include "fps.h"

typedef struct
{
        int xres;
        int yres;
        double xscale, xscalefs;
        double yscale, yscalefs;
        int videoip;
        int stretch;
        int special;
        int scanlines;
	std::string pixshader;
} CommonVS;

static CommonVS _video;
static int _fullscreen;

typedef struct
{
	char *name;
	int id;
	int xscale;
	int yscale;
	int input_bpp;
	int output_bpp;
} ScalerDefinition;

static ScalerDefinition Scalers[] = 
{

	{"hq2x", NTVB_HQ2X, 2, 2, 32, 32 },
	{"hq3x", NTVB_HQ3X, 3, 3, 32, 32 },
	{"hq4x", NTVB_HQ4X, 4, 4, 32, 32 },

	{"scale2x", NTVB_SCALE2X, 2, 2, 0, 0 },
	{"scale3x", NTVB_SCALE3X, 3, 3, 0, 0 },
	{"scale4x", NTVB_SCALE4X, 4, 4, 0, 0 },

	{"nn2x", NTVB_NN2X, 2, 2, 32, 32},
        {"nn3x", NTVB_NN3X, 3, 3, 32, 32},
        {"nn4x", NTVB_NN4X, 4, 4, 32, 32},

	{"nny2x", NTVB_NNY2X, 1, 2, 32, 32 },
	{"nny3x", NTVB_NNY3X, 1, 3, 32, 32 },
	{"nny4x", NTVB_NNY4X, 1, 4, 32, 32 },
	{ 0 }
};

static MDFNGI *VideoGI;

static int cur_xres, cur_yres, cur_flags;

static ScalerDefinition *CurrentScaler = NULL;

static SDL_Surface *OSDSurface;

static SDL_Surface *source_surface;
static SDL_Surface *screen = NULL;
static SDL_Surface *IconSurface=NULL;

static SDL_Rect src_rect;
static SDL_Rect dest_rect;
static SDL_Rect OSDRect;

static int curbpp;
static int inited=0;

static double exs,eys;
static int exres, eyres;
static int evideoip;

void ClearVideoSurfaces(void)
{
 SDL_Surface *scr = screen;

 if(!scr) 
  return;

 if(cur_flags & SDL_OPENGL)
 {
  ClearGLSurfaces(scr);
  return;
 }

 int b = 0;
 int y;

 if(scr->flags & SDL_DOUBLEBUF)
  b++;

 do
 {
  if(SDL_MUSTLOCK(scr))
   if(SDL_LockSurface(scr))
    return;

  for(y=0;y<scr->h;y++)
   memset((uint8 *)scr->pixels + scr->pitch * y, 0, scr->w);

  if(SDL_MUSTLOCK(scr))
   SDL_UnlockSurface(scr);

  SDL_UpdateRect(scr, 0, 0, scr->w, scr->h);

  PumpWrap();

  if(scr->flags&SDL_DOUBLEBUF)
   SDL_Flip(scr);
 } while(b--);

}

/* Return 1 if video was killed, 0 otherwise(video wasn't initialized). */
int KillVideo(int subsys)
{
 if(IconSurface)
 {
  SDL_FreeSurface(IconSurface);
  IconSurface = NULL;
 }

 if(source_surface)
 {
  source_surface->pixels = NULL;
  SDL_FreeSurface(source_surface);
  source_surface = NULL;
 }

 if(OSDSurface)
 {
  OSDSurface->pixels = NULL;
  SDL_FreeSurface(OSDSurface);
  OSDSurface = NULL;
 }

 if(inited&1)
 {
  if(cur_flags & SDL_OPENGL)
   KillOpenGL();
  else
  {

  }
  inited&=~1;
  return(1);
 }
 inited=0;

 SDL_WM_SetCaption("Mednafen","Mednafen");

 VideoGI = NULL;
 return(0);
}

static void GenerateRects(MDFN_Rect &DisplayRect)
{
 src_rect.x = DisplayRect.x;
 src_rect.w = DisplayRect.w;

 src_rect.y = DisplayRect.y;
 src_rect.h = DisplayRect.h;

 if(_video.stretch && _fullscreen)
 {
  src_rect.x = DisplayRect.x;
  src_rect.w = DisplayRect.w;

  src_rect.y = DisplayRect.y;
  src_rect.h = DisplayRect.h;

  dest_rect.x = 0;
  dest_rect.w = exres;
  exs = (double)exres / src_rect.w;

  dest_rect.y = 0;
  dest_rect.h = eyres;
  eys = (double)eyres / src_rect.h;
 }
 else
 {
  if(VideoGI->rotated)
  {
   int ny = (int)((eyres - DisplayRect.w * eys) / 2);
   int nx = (int)((exres - src_rect.h * exs) / 2);

   if(ny < 0) ny = 0;
   if(nx < 0) nx = 0;

   dest_rect.x = _fullscreen ? nx : 0;
   dest_rect.y = _fullscreen ? ny : 0;
   dest_rect.w = (Uint16)(src_rect.h * exs);
   dest_rect.h = (Uint16)(DisplayRect.w * eys);
  }
  else
  {
   if(_fullscreen)
    dest_rect.x = (Uint16)((exres - VideoGI->width * exs) / 2);
   else
    dest_rect.x = 0;

   dest_rect.w = (Uint16)(VideoGI->width * exs);

   int ny = (int)((eyres - src_rect.h * eys) / 2);

   if(ny < 0) ny = 0;

   dest_rect.y = _fullscreen ? ny : 0;
   dest_rect.h = (Uint16)(src_rect.h * eys);
  }
 }
}

int VideoResize(int nw, int nh)
{
 return(1);
}

int GetSpecialScalerID(const std::string &special_string)
{
 int ret = -1;

 if(special_string == "" || !strcasecmp(special_string.c_str(), "none") || special_string == "0")
  ret = 0;
 else
 {
  ScalerDefinition *scaler = Scalers;

  while(scaler->name)
  {
   char tmpstr[16];

   sprintf(tmpstr, "%d", scaler->id);

   if(!strcasecmp(scaler->name, special_string.c_str()) || tmpstr == special_string)
   {
    ret = scaler->id;
    break;
   }
   scaler++;
  }
 }
 return(ret);
}

bool MDFND_ValidateSpecialScalerSetting(const char *name, const char *value)
{
 if(GetSpecialScalerID(value) < 0)
  return(0);

 return(1);
}


static uint32 real_rs, real_gs, real_bs, real_as;

int InitVideo(MDFNGI *gi)
{
 const SDL_VideoInfo *vinf;
 int flags=0;
 int desbpp;

 VideoGI = gi;

 MDFNI_printf(_("Initializing video...\n"));
 MDFN_indent(1);

 std::string special_string = MDFN_GetSettingS(std::string(std::string(gi->shortname) + "." + std::string("special")).c_str());

 _fullscreen = MDFN_GetSettingB("fs");
 _video.xres = MDFN_GetSettingUI(std::string(std::string(gi->shortname) + "." + std::string("xres")).c_str());
 _video.yres = MDFN_GetSettingUI(std::string(std::string(gi->shortname) + "." + std::string("yres")).c_str());
 _video.xscale = MDFN_GetSettingF(std::string(std::string(gi->shortname) + "." + std::string("xscale")).c_str());
 _video.yscale = MDFN_GetSettingF(std::string(std::string(gi->shortname) + "." + std::string("yscale")).c_str());
 _video.xscalefs = MDFN_GetSettingF(std::string(std::string(gi->shortname) + "." + std::string("xscalefs")).c_str());
 _video.yscalefs = MDFN_GetSettingF(std::string(std::string(gi->shortname) + "." + std::string("yscalefs")).c_str());
 _video.videoip = MDFN_GetSettingB(std::string(std::string(gi->shortname) + "." + std::string("videoip")).c_str());
 _video.stretch = MDFN_GetSettingB(std::string(std::string(gi->shortname) + "." + std::string("stretch")).c_str());
 _video.scanlines = MDFN_GetSettingUI(std::string(std::string(gi->shortname) + "." + std::string("scanlines")).c_str());

 _video.special = GetSpecialScalerID(special_string);

 #ifdef MDFN_WANT_OPENGL_SHADERS
 _video.pixshader = MDFN_GetSettingS(std::string(std::string(gi->shortname) + "." + std::string("pixshader")).c_str());
 #else
 _video.pixshader = "none";
 #endif

 CurrentScaler = _video.special ? &Scalers[_video.special - 1] : NULL;

 if(!(SDL_WasInit(SDL_INIT_VIDEO)&SDL_INIT_VIDEO))
  if(SDL_InitSubSystem(SDL_INIT_VIDEO)==-1)
  {
   MDFND_PrintError(SDL_GetError());
   MDFN_indent(-1);
   return(0);
  }

 inited|=1;

 vinf=SDL_GetVideoInfo();

 if(vinf->hw_available)
  flags|=SDL_HWSURFACE;

 if(_fullscreen)
  flags|=SDL_FULLSCREEN;

 unsigned int vdriver = MDFN_GetSettingUI("vdriver");

 if(MDFN_GetSettingUI("doublebuf"))
 {
  if(vdriver == 0)
   SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
  else
   flags |= SDL_DOUBLEBUF;
 }

 if(vdriver == 0)
 {
  if(sdlhaveogl)
   flags |= SDL_OPENGL;
  else
   MDFN_PrintError(_("Could not load OpenGL library, disabling OpenGL usage!"));
 }
 exres = _video.xres;
 eyres = _video.yres;
 exs = _fullscreen ? _video.xscalefs : _video.xscale;
 eys = _fullscreen ? _video.yscalefs : _video.yscale;
 evideoip = _video.videoip;

 desbpp = 32;

 GenerateRects(VideoGI->DisplayRect);

 if(exs > 20)
 {
  MDFND_PrintError(_("Eep!  Effective X scale setting is way too high.  Correcting."));
  exs = 20;
  GenerateRects(VideoGI->DisplayRect);
 }
 
 if(eys > 20)
 {
  MDFND_PrintError(_("Eep!  Effective Y scale setting is way too high.  Correcting."));
  eys = 20;
  GenerateRects(VideoGI->DisplayRect);
 }

 if(_fullscreen)
 {
  if(!screen || cur_xres != exres || cur_yres != eyres || cur_flags != flags || curbpp != desbpp)
  {
   //MDFNI_DispMessage((UTF8 *)"%d %d %d %d %d %d",cur_xres, _xres, cur_yres, _yres, curbpp, desbpp);
   if(!(screen = SDL_SetVideoMode(exres, eyres, desbpp, flags)))
   {
    MDFND_PrintError(SDL_GetError()); 

    /* A last-ditch effort. */
    if(exres != 640 || eyres != 480)
    {
     if(exs > 2) exs = 2;
     if(eys > 2) eys = 2;
     exres = 640;
     eyres = 480;
     GenerateRects(VideoGI->DisplayRect);
    }
    MDFN_indent(-1);
    return(0);
   }
  }
  cur_xres = exres;
  cur_yres = eyres;
 }
 else
 {
  if(!screen || cur_xres != dest_rect.w || cur_yres != dest_rect.h || cur_flags != flags || curbpp != desbpp)
   screen = SDL_SetVideoMode(dest_rect.w, dest_rect.h, desbpp, flags);
  cur_xres = dest_rect.w;
  cur_yres = dest_rect.h;
 }

 if(!screen)
 {
  MDFND_PrintError(SDL_GetError());
  KillVideo(1);
  MDFN_indent(-1);
  return(0);
 }
 cur_flags = flags;
 curbpp = screen->format->BitsPerPixel;

 inited=1;

 MDFN_printf(_("Video Mode: %d x %d x %d bpp\n"),screen->w,screen->h,screen->format->BitsPerPixel);
 if(curbpp!=16 && curbpp!=24 && curbpp!=32)
 {
  MDFN_printf(_("Sorry, %dbpp modes are not supported by Mednafen.  Supported bit depths are 16bpp, 24bpp, and 32bpp.\n"),curbpp);
  KillVideo(1);
  MDFN_indent(-1);
  return(0);
 }
 MDFN_printf(_("OpenGL: %s\n"), (cur_flags & SDL_OPENGL) ? _("Yes") : _("No"));

 if(cur_flags & SDL_OPENGL)
 {
  MDFN_indent(1);
  MDFN_printf(_("Pixel shader: %s\n"), _video.pixshader.c_str());
  MDFN_indent(-1);
 }

 MDFN_printf(_("Fullscreen: %s\n"), _fullscreen ? _("Yes") : _("No"));
 MDFN_printf(_("Special Scaler: %s\n"), _video.special ? Scalers[_video.special - 1].name : _("None"));
 if(!_video.scanlines)
  MDFN_printf(_("Scanlines: Off\n"));
 else
  MDFN_printf(_("Scanlines: %f%% transparency\n"), 100.0f - (100.0f / _video.scanlines));

 MDFN_printf(_("Destination Rectangle: X=%d, Y=%d, W=%d, H=%d\n"), dest_rect.x, dest_rect.y, dest_rect.w, dest_rect.h);
 if(dest_rect.x < 0 || dest_rect.y < 0 || (dest_rect.x + dest_rect.w) > screen->w || (dest_rect.y + dest_rect.h) > screen->h)
 {
  MDFN_indent(1);
  if(cur_flags & SDL_OPENGL)   
   MDFN_printf(_("Warning:  Destination rectangle exceeds screen dimensions.  This is ok if you really do want the clipping...\n"));
  else // NonOpenGL mode doesn't support this kind of screen overflow clipping
   MDFN_printf(_("Warning:  Destination rectangle exceeds screen dimensions.  The rectangle will be adjusted to fit within the screen area.\n"));
  MDFN_indent(-1);
 }
 if(gi && gi->name)
  SDL_WM_SetCaption((char *)gi->name,(char *)gi->name);
 else
  SDL_WM_SetCaption("Mednafen","Mednafen");

 #ifdef LSB_FIRST
 IconSurface=SDL_CreateRGBSurfaceFrom((void *)mednafen_playicon.pixel_data,32,32,32,32*4,0xFF,0xFF00,0xFF0000,0xFF000000);
 #else
 IconSurface=SDL_CreateRGBSurfaceFrom((void *)mednafen_playicon.pixel_data,32,32,32,32*4,0xFF000000,0xFF0000,0xFF00,0xFF);
 #endif

 SDL_WM_SetIcon(IconSurface,0);

 if(cur_flags & SDL_OPENGL)
 {
  if(!InitOpenGL(evideoip, _video.scanlines, _video.pixshader, screen))
  {
   KillVideo(1);
   MDFN_indent(-1);
   return(0);
  }
 }
 else
 {



 }

 MDFN_indent(-1);
 SDL_ShowCursor(0);

 int rs, gs, bs, as;

 if(cur_flags & SDL_OPENGL)
 {
  #ifdef LSB_FIRST
  rs = 0;
  gs = 8;
  bs = 16;
  as = 24;
  #else
  rs = 24;
  gs = 16;
  bs = 8;
  as = 0;
  #endif
 }
 else
 {
  rs = screen->format->Rshift;
  gs = screen->format->Gshift;
  bs = screen->format->Bshift;

  as = 0;
  while(as == rs || as == gs || as == bs) // Find unused 8-bits to use as our alpha channel
   as += 8;
 }

 real_rs = rs;
 real_gs = gs;
 real_bs = bs;
 real_as = as;

 /* HQXX only supports this pixel format, sadly, and other pixel formats
    can't be easily supported without rewriting the filters.
    We do conversion to the real screen format in the blitting function. 
 */
 if(CurrentScaler)
  if(CurrentScaler->id == NTVB_HQ2X || CurrentScaler->id == NTVB_HQ3X || CurrentScaler->id == NTVB_HQ4X)
  {
   rs = 0;
   gs = 8;
   bs = 16;
   as = 24;
  }
 source_surface = SDL_CreateRGBSurfaceFrom(NULL, (VideoGI->system == GISYS_PCE) ? 512 : 256, 256, 32, gi->pitch, 0xFF << rs, 0xFF << gs, 0xFF << bs, 0xFF << as);
 OSDSurface = SDL_CreateRGBSurfaceFrom(NULL, 512, 224, 32, 512 * sizeof(uint32), 0xFF << rs, 0xFF << gs, 0xFF << bs, 0xFF << as);
 //OSDRect.w = 256;
 OSDRect.h = 224;
 OSDRect.x = 0;
 OSDRect.y = 0;

 MDFNI_SetPixelFormat(rs, gs, bs, as);

 ClearVideoSurfaces();
 return 1;
}

static void SubBlit(void)
{
   if(CurrentScaler)
   {
    uint8 *screen_pixies;
    uint32 screen_pitch;
    SDL_Surface *bah_surface = NULL;
    SDL_Rect boohoo_rect = src_rect;

    boohoo_rect.x = boohoo_rect.y = 0;
    boohoo_rect.w *= CurrentScaler->xscale;
    boohoo_rect.h *= CurrentScaler->yscale;

    bah_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, boohoo_rect.w, boohoo_rect.h, source_surface->format->BitsPerPixel, source_surface->format->Rmask, source_surface->format->Gmask, source_surface->format->Bmask, source_surface->format->Amask);

    screen_pixies = (uint8 *)bah_surface->pixels;
    screen_pitch = bah_surface->pitch;

    if(CurrentScaler->id == NTVB_SCALE4X || CurrentScaler->id == NTVB_SCALE3X || CurrentScaler->id == NTVB_SCALE2X)
    {
     uint8 *source_pixies = (uint8 *)source_surface->pixels + src_rect.x * source_surface->format->BytesPerPixel + src_rect.y * source_surface->pitch;
     scale((CurrentScaler->id ==  NTVB_SCALE2X)?2:(CurrentScaler->id == NTVB_SCALE4X)?4:3, screen_pixies, screen_pitch, source_pixies, source_surface->pitch, source_surface->format->BytesPerPixel, src_rect.w, src_rect.h);
    }
    else if(CurrentScaler->id == NTVB_NN2X || CurrentScaler->id == NTVB_NN3X || CurrentScaler->id == NTVB_NN4X)
    {
     nnx(CurrentScaler->id - NTVB_NN2X + 2, source_surface, &src_rect, bah_surface, &boohoo_rect);
    }
    else if(CurrentScaler->id == NTVB_NNY2X || CurrentScaler->id == NTVB_NNY3X || CurrentScaler->id == NTVB_NNY4X)
    {
     nnyx(CurrentScaler->id - NTVB_NNY2X + 2, source_surface, &src_rect, bah_surface, &boohoo_rect);
    }
    else 
    {
     uint8 *source_pixies = (uint8 *)source_surface->pixels + src_rect.x * source_surface->format->BytesPerPixel + src_rect.y * source_surface->pitch;

     if(CurrentScaler->id == NTVB_HQ2X)
      hq2x_32(source_pixies, screen_pixies, src_rect.w, src_rect.h, source_surface->pitch, screen_pitch);
     else if(CurrentScaler->id == NTVB_HQ3X)
      hq3x_32(source_pixies, screen_pixies, src_rect.w, src_rect.h, source_surface->pitch, screen_pitch);
     else if(CurrentScaler->id == NTVB_HQ4X)
      hq4x_32(source_pixies, screen_pixies, src_rect.w, src_rect.h, source_surface->pitch, screen_pitch);

     if(bah_surface->format->Rshift != real_rs || bah_surface->format->Gshift != real_gs ||
  	bah_surface->format->Bshift != real_bs)
     {
      uint32 *lineptr = (uint32 *)bah_surface->pixels;
      unsigned int srs = bah_surface->format->Rshift;
      unsigned int sgs = bah_surface->format->Gshift;
      unsigned int sbs = bah_surface->format->Bshift;
      unsigned int sas = bah_surface->format->Ashift;
      unsigned int drs = real_rs;
      unsigned int dgs = real_gs;
      unsigned int dbs = real_bs;
      unsigned int das = real_as;

      for(int y = 0; y < boohoo_rect.h; y++)
      {
       for(int x = 0; x < boohoo_rect.w; x++)
       {
        uint32 pixel = lineptr[x];
        lineptr[x] = (((pixel >> srs) & 0xFF) << drs) | (((pixel >> sgs) & 0xFF) << dgs) | (((pixel >> sbs) & 0xFF) << dbs);
       }
       lineptr += bah_surface->pitch >> 2;
      }
      // Also fix the OSD buffer if we're in OpenGL mode
      // SDL will take care of it in nonOpenGL mode
      // because we use SDL_BlitSurface()
      lineptr = (uint32 *)OSDSurface->pixels;
      if((cur_flags & SDL_OPENGL) && OSDSurface->pixels)
       for(int y = 0; y < 224; y++)
       {
        for(int x = 0; x < 256; x++)
        {
         uint32 pixel = lineptr[x];
         lineptr[x] = (((pixel >> srs) & 0xFF) << drs) | (((pixel >> sgs) & 0xFF) << dgs) | (((pixel >> sbs) & 0xFF) << dbs) | (((pixel >> sas) & 0xFF) << das);
        }
        lineptr += 256;
       }
      }
    }
    if(cur_flags & SDL_OPENGL)
     BlitOpenGL(bah_surface, &boohoo_rect, &dest_rect, &src_rect);
    else
     BlitNonGL(bah_surface, &boohoo_rect, &src_rect, &dest_rect, screen, _video.scanlines);
    SDL_FreeSurface(bah_surface);
   }
   else // No special scaler:
   {
    if(cur_flags & SDL_OPENGL)
     BlitOpenGL(source_surface, &src_rect, &dest_rect, &src_rect);
    else
     BlitNonGL(source_surface, &src_rect, &src_rect, &dest_rect, screen, _video.scanlines);
   }
}

void BlitScreen(uint32 *XBuf, MDFN_Rect *DisplayRect, MDFN_Rect *LineWidths, uint32 *OSDBuffer)
{
 if(!screen) return;

 GenerateRects(*DisplayRect);
 source_surface->pixels = XBuf;
 OSDSurface->pixels = OSDBuffer;

 if(OSDBuffer)
 {
  OSDRect.w = 256;
  if(Netplay_GetTextView() || IsConsoleCheatConfigActive() || Debugger_IsActive())
   OSDRect.w = 512;

  FPS_Draw(OSDSurface, &OSDRect);

  if(Debugger_IsActive())
   Debugger_Draw(OSDSurface, &OSDRect);
  else if(Netplay_GetTextView())
   DrawNetplayTextBuffer(OSDSurface, &OSDRect);
  else if(IsConsoleCheatConfigActive())
   DrawCheatConsole(OSDSurface, &OSDRect);
 }

 if(LineWidths[0].w == ~0) // Skip multi line widths code?
 {
  SubBlit();
 }
 else
 {
  int y;
  int last_y = src_rect.y;
  int last_x = LineWidths[src_rect.y].x;
  int last_width = LineWidths[src_rect.y].w;
  SDL_Rect src_rect_save;
  SDL_Rect dest_rect_save;

  for(y = src_rect.y; y < (src_rect.y + src_rect.h + 1); y++)
  {
   if(y == (src_rect.y + src_rect.h) || LineWidths[y].x != last_x || LineWidths[y].w != last_width)
   {
    src_rect_save = src_rect;
    dest_rect_save = dest_rect;
    src_rect.x = last_x;
    src_rect.w = last_width;
    src_rect.y = last_y;
    src_rect.h = y - last_y;

    dest_rect.y = dest_rect_save.y + (last_y - src_rect_save.y) * dest_rect.h / src_rect_save.h;
    dest_rect.h = src_rect.h * dest_rect.h / src_rect_save.h;

    // Blit here!
    SubBlit();

    src_rect = src_rect_save;
    dest_rect = dest_rect_save;
    last_y = y;
    last_width = LineWidths[y].w;
    last_x =  LineWidths[y].x;
   }
  }
 }

 if(OSDBuffer)
 {
  if(cur_flags & SDL_OPENGL)
  {
   BlitOpenGLOSD(OSDBuffer, &OSDRect);
  }
  else
  {
   SDL_Rect zederect;

   zederect.x = 0;
   zederect.y = 0;
   zederect.w = OSDRect.w;
   zederect.h = OSDRect.h;

   if(zederect.w > screen->w) zederect.w = screen->w;
   if(zederect.h > screen->h) zederect.h = screen->h;

   zederect.x = (screen->w - zederect.w) / 2;
   zederect.y = (screen->h - zederect.h) / 2;

   SDL_SetColorKey(OSDSurface, SDL_SRCCOLORKEY, 0);
   SDL_SetAlpha(OSDSurface, SDL_SRCALPHA, 0); //128);
   SDL_BlitSurface(OSDSurface, &OSDRect, screen, &zederect);
  }
 }
 if(!(cur_flags & SDL_OPENGL))
 {
  if(cur_flags & SDL_DOUBLEBUF)
   SDL_Flip(screen);
  else
   SDL_UpdateRect(screen, dest_rect.x, dest_rect.y, dest_rect.w, dest_rect.h);
 }
 else
  FlipOpenGL();
}

void PtoV(int *x, int *y)
{
 *y=(int)((double)*y/eys);
 *x=(int)((double)*x/exs);
}

