1292 lines
35 KiB
C++
1292 lines
35 KiB
C++
/*
|
|
* video.cpp
|
|
*
|
|
* Copyright (C) 2001 Matt Ownby
|
|
*
|
|
* This file is part of DAPHNE, a laserdisc arcade game emulator
|
|
*
|
|
* DAPHNE 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.
|
|
*
|
|
* DAPHNE 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
|
|
*/
|
|
|
|
// video.cpp
|
|
// Part of the DAPHNE emulator
|
|
// This code started by Matt Ownby, May 2000
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <string> // for some error messages
|
|
#include <SDL_syswm.h> // rdg2010
|
|
#include "video.h"
|
|
#include "palette.h"
|
|
#include "SDL_DrawText.h"
|
|
#include "../io/conout.h"
|
|
#include "../io/error.h"
|
|
#include "../io/mpo_fileio.h"
|
|
#include "../io/mpo_mem.h"
|
|
#include "SDL_Console.h"
|
|
#include "../game/game.h"
|
|
#include "../ldp-out/ldp.h"
|
|
#include "../ldp-out/ldp-vldp-gl.h"
|
|
#include "../io/homedir.h"
|
|
|
|
|
|
#ifdef USE_OPENGL
|
|
#ifdef MAC_OSX
|
|
#include <glew.h>
|
|
#else
|
|
#include <GL/glew.h>
|
|
#endif
|
|
|
|
|
|
// This is the max width and height that any .BMP will be, so that we can fit it into
|
|
// an opengl texture. If you need to display a bigger .BMP, increase this number.
|
|
// NOTE : this number must be a power of 2!!!
|
|
#define GL_TEX_SIZE 1024
|
|
|
|
// pointer to the buffer that we allocate for bitmap blits
|
|
Uint8 *g_pVidTex = NULL;
|
|
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
#ifndef GP2X
|
|
unsigned int g_vid_width = 640, g_vid_height = 480; // default video width and video height
|
|
#ifdef DEBUG
|
|
const Uint16 cg_normalwidths[] = { 320, 640, 800, 1024, 1280, 1280, 1600 };
|
|
const Uint16 cg_normalheights[]= { 240, 480, 600, 768, 960, 1024, 1200 };
|
|
#else
|
|
const Uint16 cg_normalwidths[] = { 640, 800, 1024, 1280, 1280, 1600 };
|
|
const Uint16 cg_normalheights[]= { 480, 600, 768, 960, 1024, 1200 };
|
|
#endif // DEBUG
|
|
#else
|
|
unsigned int g_vid_width = 320, g_vid_height = 240; // default for gp2x
|
|
const Uint16 cg_normalwidths[] = { 320 };
|
|
const Uint16 cg_normalheights[]= { 240 };
|
|
#endif
|
|
|
|
// the dimensions that we draw (may differ from g_vid_width/height if aspect ratio is enforced)
|
|
unsigned int g_draw_width = 640, g_draw_height = 480;
|
|
|
|
SDL_Surface *g_led_bmps[LED_RANGE] = { 0 };
|
|
SDL_Surface *g_other_bmps[B_EMPTY] = { 0 };
|
|
SDL_Surface *g_screen = NULL; // our primary display
|
|
SDL_Surface *g_screen_blitter = NULL; // the surface we blit to (we don't blit directly to g_screen because opengl doesn't like that)
|
|
bool g_console_initialized = false; // 1 once console is initialized
|
|
bool g_fullscreen = false; // whether we should initialize video in fullscreen mode or not
|
|
bool g_fakefullscreen = false; // by RDG2010 -- whether daphne should do fullscreen window
|
|
int g_scalefactor = 100; // by RDG2010 -- scales the image to this percentage value (for CRT TVs with overscan problems).
|
|
int sboverlay_characterset = 1;
|
|
|
|
// whether we will try to force a 4:3 aspect ratio regardless of window size
|
|
// (this is probably a good idea as a default option)
|
|
bool g_bForceAspectRatio = true;
|
|
|
|
bool g_bUseOpenGL = false; // whether user has requested we use OpenGL
|
|
|
|
// the # of degrees to rotate counter-clockwise in opengl mode
|
|
float g_fRotateDegrees = 0.0;
|
|
|
|
#ifdef USE_OPENGL
|
|
GLuint g_texture_id = 0; // for any blits we have to do in opengl ...
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// initializes the window in which we will draw our BMP's
|
|
// returns true if successful, false if failure
|
|
bool init_display()
|
|
{
|
|
|
|
bool result = false; // whether video initialization is successful or not
|
|
bool abnormalscreensize = true; // assume abnormal
|
|
const SDL_VideoInfo *vidinfo = NULL;
|
|
Uint8 suggested_bpp = 0;
|
|
Uint32 sdl_flags = 0; // the default for this depends on whether we are using HW accelerated YUV overlays or not
|
|
|
|
char *hw_env = getenv("SDL_VIDEO_YUV_HWACCEL");
|
|
|
|
// if HW acceleration has been disabled, we need to use a SW surface due to some oddities with crashing and fullscreen
|
|
if (hw_env && (hw_env[0] == '0'))
|
|
{
|
|
sdl_flags = SDL_SWSURFACE;
|
|
}
|
|
|
|
// else if HW acceleration hasn't been explicitely disabled ...
|
|
else
|
|
{
|
|
|
|
sdl_flags = SDL_HWSURFACE;
|
|
// Win32 notes (may not apply to linux) :
|
|
// After digging around in the SDL source code, I've discovered a few things ...
|
|
// When using fullscreen mode, you should always use SDL_HWSURFACE because otherwise
|
|
// you can't use YUV hardware overlays due to SDL creating an extra surface without
|
|
// your consent (which seems retarded to me hehe).
|
|
// SDL_SWSURFACE + hw accelerated YUV overlays will work in windowed mode, but might
|
|
// as well just use SDL_HWSURFACE for everything.
|
|
}
|
|
|
|
char s[250] = { 0 };
|
|
Uint32 x = 0; // temporary index
|
|
|
|
// if we were able to initialize the video properly
|
|
if ( SDL_InitSubSystem(SDL_INIT_VIDEO) >=0 )
|
|
{
|
|
|
|
vidinfo = SDL_GetVideoInfo();
|
|
suggested_bpp = vidinfo->vfmt->BitsPerPixel;
|
|
|
|
// if we were in 8-bit mode, try to get at least 16-bit color
|
|
// because we definitely use more than 256 colors in daphne
|
|
if (suggested_bpp < 16)
|
|
{
|
|
suggested_bpp = 32;
|
|
}
|
|
|
|
// By RDG2010
|
|
// Have cursor disabled always.
|
|
// Useful for ALG SINGE games
|
|
// If there is a game that needs to show the cursor icon of the OS
|
|
// then modify.
|
|
SDL_ShowCursor(SDL_DISABLE); // hide mouse in fullscreen mode
|
|
|
|
if (g_fullscreen)
|
|
{
|
|
//SDL_ShowCursor(SDL_DISABLE); // hide mouse in fullscreen mode
|
|
sdl_flags |= SDL_FULLSCREEN;
|
|
}
|
|
|
|
// go through each standard resolution size to see if we are using a standard resolution
|
|
for (x=0; x < (sizeof(cg_normalwidths) / sizeof(Uint16)); x++)
|
|
{
|
|
// if we find a match, we know we're using a standard res
|
|
if ((g_vid_width == cg_normalwidths[x]) && (g_vid_height == cg_normalheights[x]))
|
|
{
|
|
abnormalscreensize = false;
|
|
}
|
|
}
|
|
|
|
// if we're using a non-standard resolution
|
|
if (abnormalscreensize)
|
|
{
|
|
printline("WARNING : You have specified an abnormal screen resolution! Normal screen resolutions are:");
|
|
// print each standard resolution
|
|
for (x=0; x < (sizeof(cg_normalwidths) / sizeof(Uint16)); x++)
|
|
{
|
|
sprintf(s,"%d x %d", cg_normalwidths[x], cg_normalheights[x]);
|
|
printline(s);
|
|
}
|
|
newline();
|
|
}
|
|
|
|
/* by RDG2010
|
|
* Adding preliminary lightgun support.
|
|
* For now that means a fake fullscreen.
|
|
* A borderless, no title bar window the same size as the desktop.
|
|
* This is done in three steps:
|
|
* 1. Get desktop resolution.
|
|
* 2. Make SDL window borderless.
|
|
* 3. Move window to top-left corner of the screen.
|
|
*
|
|
* Tested OK on both Windows and Ubuntu Linux.
|
|
* TODO: Provide a better solution.
|
|
*
|
|
*/
|
|
|
|
if (get_fakefullscreen())
|
|
{
|
|
|
|
// Step 1. Get desktop resolution.
|
|
// Get the current resolution of the system's desktop.
|
|
const SDL_VideoInfo* info = SDL_GetVideoInfo(); // For SDL 1.3 use SDL_GetDesktopDisplayMode() instead.
|
|
int desktopWidth = info->current_w;
|
|
int desktopHeight = info->current_h;
|
|
// Update variables here, before initializing any surfaces.
|
|
g_vid_width = desktopWidth ; g_vid_height = desktopHeight;
|
|
}
|
|
// RDG2010
|
|
|
|
g_draw_width = g_vid_width;
|
|
g_draw_height = g_vid_height;
|
|
|
|
// if we're supposed to enforce the aspect ratio ...
|
|
if (g_bForceAspectRatio)
|
|
{
|
|
double dCurAspectRatio = (double) g_vid_width / g_vid_height;
|
|
const double dTARGET_ASPECT_RATIO = 4.0/3.0;
|
|
|
|
// if current aspect ratio is less than 1.3333
|
|
if (dCurAspectRatio < dTARGET_ASPECT_RATIO)
|
|
{
|
|
g_draw_height = (g_draw_width * 3) / 4;
|
|
}
|
|
// else if current aspect ratio is greater than 1.3333
|
|
else if (dCurAspectRatio > dTARGET_ASPECT_RATIO)
|
|
{
|
|
g_draw_width = (g_draw_height * 4) / 3;
|
|
}
|
|
// else the aspect ratio is already correct, so don't change anything
|
|
}
|
|
|
|
// if we're supposed to scale the image...
|
|
if (g_scalefactor < 100)
|
|
{
|
|
g_draw_width = g_draw_width * g_scalefactor / 100;
|
|
g_draw_height = g_draw_height * g_scalefactor / 100;
|
|
}
|
|
|
|
#ifndef GP2X
|
|
if (!g_bUseOpenGL)
|
|
{
|
|
#ifdef WIN32
|
|
if (g_game->verify_required_file2("singe32.bmp","pics",0xC17A933D))
|
|
{
|
|
// Add icon to the SDL Window -- RDG
|
|
|
|
Uint32 colorkey;
|
|
SDL_Surface *image;
|
|
image = SDL_LoadBMP("pics/singe32.bmp");
|
|
colorkey = SDL_MapRGB(image->format, 255, 0, 255);
|
|
SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
|
|
SDL_WM_SetIcon(image,NULL); // MUST BE CALLED BEFORE set video mode, or else it won't show on the title bar.
|
|
|
|
}
|
|
|
|
#endif
|
|
// by RDG2010
|
|
// Step 2. Create a borderless SDL window.
|
|
// If doing fullscreen window, make the window bordeless (no title bar).
|
|
// This is achieved by adding the SDL_NOFRAME flag.
|
|
|
|
if (get_fakefullscreen()) sdl_flags = sdl_flags | SDL_NOFRAME;
|
|
|
|
g_screen = SDL_SetVideoMode(g_vid_width, g_vid_height, suggested_bpp, sdl_flags);
|
|
SDL_WM_SetCaption("SINGE: Somewhat Interactive Nostalgic Game Engine =]", "Singe");
|
|
|
|
}
|
|
else
|
|
{
|
|
#ifdef USE_OPENGL
|
|
init_opengl();
|
|
glGenTextures(1, &g_texture_id); // generate texture buffer for use in this file
|
|
g_pVidTex = MPO_MALLOC(GL_TEX_SIZE * GL_TEX_SIZE * 4); // 32-bit bits per pixel, width and height the same
|
|
#endif
|
|
}
|
|
#else
|
|
SDL_ShowCursor(SDL_DISABLE); // always hide mouse for gp2x
|
|
g_screen = SDL_SetVideoMode(320, 240, 0, SDL_HWSURFACE);
|
|
#endif
|
|
|
|
/* by RDG2010
|
|
* Step 3. Move window to the top-left corner of the screen.
|
|
*
|
|
* The task of positioning the window is OS dependant.
|
|
* When using a window the same size of the desktop, X11 will
|
|
* automatically position it to the top-left corner of the screen.
|
|
* In the case of Windows, it has to be done manually.
|
|
*
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
if (get_fakefullscreen())
|
|
{
|
|
|
|
// Access to SDL's OS specific structure.
|
|
SDL_SysWMinfo windowInfo;
|
|
SDL_VERSION(&windowInfo.version);
|
|
|
|
if(SDL_GetWMInfo(&windowInfo))
|
|
{
|
|
// Retrieve the Windows handle to the SDL window.
|
|
HWND handle = windowInfo.window;
|
|
// Position Window to top-left corner of the screen.
|
|
if(!SetWindowPos(handle, NULL, 0, 0, 0, 0, SWP_NOREPOSITION|SWP_NOZORDER|SWP_NOSIZE))
|
|
{
|
|
printline("Error occurred with 'SetWindowPos'. Fullscreen window failed.");
|
|
result = 0;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// Error occurred with 'SDL_GetWMInfo'
|
|
printline("Error occurred with 'SDL_GetWMInfo'. Fullscreen window failed.");
|
|
result = 0;
|
|
|
|
} // endif
|
|
|
|
} // endif
|
|
|
|
#endif
|
|
|
|
|
|
// create a 32-bit surface
|
|
g_screen_blitter = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
g_vid_width,
|
|
g_vid_height,
|
|
32,
|
|
0xff, 0xFF00, 0xFF0000, 0xFF000000);
|
|
|
|
if (g_screen && g_screen_blitter)
|
|
{
|
|
SDL_SetAlpha(g_screen_blitter,SDL_SRCALPHA,0); //rdg
|
|
sprintf(s, "Set %dx%d at %d bpp with flags: %x", g_screen->w, g_screen->h, g_screen->format->BitsPerPixel, g_screen->flags);
|
|
printline(s);
|
|
|
|
// initialize SDL console in the background
|
|
if (ConsoleInit("pics/ConsoleFont.bmp", g_screen_blitter, 100)==0)
|
|
{
|
|
AddCommand(g_cpu_break, "break");
|
|
g_console_initialized = true;
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
printerror("Error initializing SDL console =(");
|
|
}
|
|
|
|
// sometimes the screen initializes to white, so this attempts to prevent that
|
|
vid_blank();
|
|
vid_flip();
|
|
vid_blank();
|
|
vid_flip();
|
|
}
|
|
}
|
|
|
|
if (result == 0)
|
|
{
|
|
sprintf(s, "Could not initialize video display: %s", SDL_GetError());
|
|
printerror(s);
|
|
}
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
#ifdef USE_OPENGL
|
|
bool init_opengl()
|
|
{
|
|
bool bResult = false;
|
|
|
|
Uint32 sdl_flags = SDL_SWSURFACE | SDL_OPENGL;
|
|
|
|
// fullscreen is broken
|
|
if (get_fullscreen()) sdl_flags |= SDL_FULLSCREEN;
|
|
|
|
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
|
|
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
|
|
|
// by RDG2010
|
|
// Step 2. Create a borderless SDL window (on the OpenGL side).
|
|
// If doing fullscreen window, make the window bordeless (no title bar).
|
|
// This is achieved by adding the SDL_NOFRAME flag.
|
|
// Tested OK on both Windows and Ubuntu Linux.
|
|
|
|
if (get_fakefullscreen()) sdl_flags = sdl_flags | SDL_NOFRAME;
|
|
|
|
g_screen = SDL_SetVideoMode(g_vid_width, g_vid_height, 0, sdl_flags);
|
|
|
|
// if SDL_SetVideoMode worked ...
|
|
if (g_screen)
|
|
{
|
|
//SDL_WM_SetCaption("DAPHNE: Now in experimental OpenGL mode :)", "daphne");
|
|
SDL_WM_SetCaption("SINGE: Somewhat Interactive Nostalgic Game Engine =]", "Singe");
|
|
|
|
//glShadeModel(GL_SMOOTH);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_NORMALIZE); // since we are doing scaling, we need this ...
|
|
glFrontFace(GL_CCW);
|
|
glCullFace(GL_BACK);
|
|
glEnable(GL_CULL_FACE); // this should give us some optimization for free
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
/* Set the clear color. */
|
|
glClearColor( 0, 0.0, 0, 1 );
|
|
|
|
/* Setup our viewport. */
|
|
glViewport( 0, 0, g_screen->w, g_screen->h );
|
|
|
|
// ENABLE 2D MODE (ORTHO)
|
|
glMatrixMode (GL_PROJECTION);
|
|
glLoadIdentity();
|
|
|
|
// The idea is to have the center of the image be at 0,0 to make rotation, scaling, etc
|
|
// easier.
|
|
glOrtho(
|
|
-g_screen->w / 2, // left
|
|
g_screen->w / 2, // right
|
|
-g_screen->h / 2, // bottom
|
|
g_screen->h / 2, // top
|
|
-10, 10);
|
|
|
|
glMatrixMode (GL_MODELVIEW);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
// handle optional rotation
|
|
// if we're to one side or the other, scale the image so it will fit
|
|
if ((g_fRotateDegrees == 90.0) || (g_fRotateDegrees == 270.0))
|
|
{
|
|
// NOTE : this can either shrink or enlarge depending on whether the width or height is bigger
|
|
GLfloat fFactor = (GLfloat) g_vid_height / g_vid_width;
|
|
glScalef(fFactor, fFactor, 1.0);
|
|
}
|
|
|
|
// only rotate if we have a need to
|
|
if (g_fRotateDegrees != 0)
|
|
{
|
|
glRotatef(g_fRotateDegrees, 0, 0, 1.0);
|
|
}
|
|
|
|
bResult = true;
|
|
}
|
|
// else SetVideoMode failed ...
|
|
|
|
return bResult;
|
|
}
|
|
#endif // USE_OPENGL
|
|
|
|
// shuts down video display
|
|
void shutdown_display()
|
|
{
|
|
printline("Shutting down video display...");
|
|
|
|
if (g_console_initialized)
|
|
{
|
|
ConsoleShutdown();
|
|
g_console_initialized = false;
|
|
}
|
|
|
|
#ifdef USE_OPENGL
|
|
// free texture buffer from memory
|
|
MPO_FREE(g_pVidTex);
|
|
#endif
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
}
|
|
|
|
void vid_flip()
|
|
{
|
|
// if we're not using OpenGL, then just use the regular SDL Flip ...
|
|
if (!g_bUseOpenGL)
|
|
{
|
|
SDL_Flip(g_screen);
|
|
}
|
|
else
|
|
{
|
|
SDL_GL_SwapBuffers();
|
|
}
|
|
}
|
|
|
|
void vid_blank()
|
|
{
|
|
if (!g_bUseOpenGL)
|
|
{
|
|
SDL_FillRect(g_screen, NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
#ifdef USE_OPENGL
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef USE_OPENGL
|
|
// converts an SDL surface to an opengl texture
|
|
void vid_srf2tex(SDL_Surface *srf, GLuint uTexID)
|
|
{
|
|
Uint8 *ptrPixelRow = (Uint8 *) srf->pixels;
|
|
Uint32 *RGBARow = (Uint32 *) g_pVidTex;
|
|
Uint32 *g_puRGBAPalette = get_rgba_palette();
|
|
for (unsigned int uRow = 0; (uRow < (unsigned) srf->h) && (uRow < GL_TEX_SIZE); ++uRow)
|
|
{
|
|
Uint8 *ptrPixel = ptrPixelRow;
|
|
Uint32 *RGBA = RGBARow;
|
|
|
|
for (unsigned int uCol = 0; (uCol < (unsigned) srf->w) && (uCol < GL_TEX_SIZE); ++uCol)
|
|
{
|
|
Uint8 R, G, B;
|
|
|
|
// if this is an 8-bit surface
|
|
if (srf->format->BitsPerPixel == 8)
|
|
{
|
|
// retrieve precalculated RGBA value
|
|
*RGBA = g_puRGBAPalette[*ptrPixel];
|
|
}
|
|
// else it doesn't use a color palette
|
|
else
|
|
{
|
|
Uint32 uVal = *((Uint32*) ptrPixel);
|
|
R = ((uVal & srf->format->Rmask) >> srf->format->Rshift) << srf->format->Rloss;
|
|
G = ((uVal & srf->format->Gmask) >> srf->format->Gshift) << srf->format->Gloss;
|
|
B = ((uVal & srf->format->Bmask) >> srf->format->Bshift) << srf->format->Bloss;
|
|
// this may not work for big endian, but we won't know until we try
|
|
*RGBA = R | (G << 8) | (B << 16) | 0xFF000000;
|
|
}
|
|
|
|
// move to the next pixel ...
|
|
ptrPixel += srf->format->BytesPerPixel;
|
|
++RGBA;
|
|
} // end this line
|
|
|
|
// move to the next row
|
|
ptrPixelRow += srf->pitch;
|
|
RGBARow += GL_TEX_SIZE; // move down one row in the texture memory
|
|
}
|
|
|
|
glBindTexture(GL_TEXTURE_2D, uTexID);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
// apply the texture
|
|
glTexImage2D(GL_TEXTURE_2D,
|
|
0, // level is 0
|
|
GL_RGBA, GL_TEX_SIZE, GL_TEX_SIZE,
|
|
0, // border is 0
|
|
GL_RGBA, GL_UNSIGNED_BYTE, g_pVidTex);
|
|
|
|
}
|
|
#endif
|
|
|
|
void vid_blit(SDL_Surface *srf, int x, int y)
|
|
{
|
|
// if (g_ldp->is_blitting_allowed()) rdg
|
|
int result = 0;
|
|
{
|
|
if (!g_bUseOpenGL)
|
|
{
|
|
SDL_Rect dest;
|
|
dest.x = (short) x;
|
|
dest.y = (short) y;
|
|
dest.w = (unsigned short) srf->w;
|
|
dest.h = (unsigned short) srf->h;
|
|
result = SDL_BlitSurface(srf, NULL, g_screen, &dest);
|
|
}
|
|
|
|
// else, OpenGL mode for blitting ...
|
|
else
|
|
{
|
|
#ifdef USE_OPENGL
|
|
|
|
// convert surface to a texture
|
|
vid_srf2tex(srf, g_texture_id);
|
|
|
|
// draw the textured rectangle
|
|
GLfloat fWidth = (GLfloat) srf->w / GL_TEX_SIZE;
|
|
GLfloat fHeight = (GLfloat) srf->h / GL_TEX_SIZE;
|
|
|
|
// convert y from top-to-bottom to bottom-to-top (SDL -> openGL)
|
|
y = g_vid_height - y;
|
|
|
|
// adjust coordinates so they match up with glOrtho projection
|
|
x -= (g_vid_width >> 1);
|
|
y -= (g_vid_height >> 1);
|
|
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0, 0); glVertex3i(x, y, 0); // top left
|
|
glTexCoord2f(0, fHeight); glVertex3i(x, y - srf->h, 0); // bottom left
|
|
glTexCoord2f(fWidth, fHeight); glVertex3i(x + srf->w, y - srf->h, 0); // bottom right
|
|
glTexCoord2f(fWidth, 0); glVertex3i(x + srf->w, y, 0); // top right
|
|
glEnd();
|
|
|
|
#endif // USE_OPENGL
|
|
}
|
|
}
|
|
// else blitting isn't allowed, so just ignore
|
|
}
|
|
|
|
// redraws the proper display (Scoreboard, etc) on the screen, after first clearing the screen
|
|
// call this every time you want the display to return to normal
|
|
void display_repaint()
|
|
{
|
|
vid_blank();
|
|
vid_flip();
|
|
g_game->video_force_blit();
|
|
}
|
|
|
|
// loads all the .bmp's used by DAPHNE
|
|
// returns true if they were all successfully loaded, or a false if they weren't
|
|
bool load_bmps()
|
|
{
|
|
|
|
bool result = true; // assume success unless we hear otherwise
|
|
int index = 0;
|
|
char filename[81];
|
|
/*
|
|
for (; index < LED_RANGE; index++)
|
|
{
|
|
sprintf(filename, "pics/led%d.bmp", index);
|
|
|
|
g_led_bmps[index] = load_one_bmp(filename);
|
|
|
|
// If the bit map did not successfully load
|
|
if (g_led_bmps[index] == 0)
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
g_other_bmps[B_DL_PLAYER1] = load_one_bmp("pics/player1.bmp");
|
|
g_other_bmps[B_DL_PLAYER2] = load_one_bmp("pics/player2.bmp");
|
|
g_other_bmps[B_DL_LIVES] = load_one_bmp("pics/lives.bmp");
|
|
g_other_bmps[B_DL_CREDITS] = load_one_bmp("pics/credits.bmp");
|
|
*/
|
|
g_other_bmps[B_DAPHNE_SAVEME] = load_one_bmp("pics/saveme.bmp");
|
|
g_other_bmps[B_GAMENOWOOK] = load_one_bmp("pics/gamenowook.bmp");
|
|
/*
|
|
if (sboverlay_characterset != 2)
|
|
g_other_bmps[B_OVERLAY_LEDS] = load_one_bmp("pics/overlayleds1.bmp");
|
|
else
|
|
g_other_bmps[B_OVERLAY_LEDS] = load_one_bmp("pics/overlayleds2.bmp");
|
|
|
|
g_other_bmps[B_OVERLAY_LDP1450] = load_one_bmp("pics/ldp1450font.bmp");
|
|
*/
|
|
// check to make sure they all loaded
|
|
//for (index = 0; index < B_EMPTY; index++)
|
|
for (index = 0; index < 2; index++)
|
|
{
|
|
if (g_other_bmps[index] == NULL)
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
SDL_Surface *load_one_bmp(const char *filename)
|
|
{
|
|
SDL_Surface *result = SDL_LoadBMP(filename);
|
|
|
|
if (!result)
|
|
{
|
|
string err = "Could not load bitmap : ";
|
|
err = err + filename;
|
|
printerror(err.c_str());
|
|
}
|
|
|
|
return(result);
|
|
}
|
|
|
|
// Draw's one of our LED's to the screen
|
|
// value contains the bitmap to draw (0-9 is valid)
|
|
// x and y contain the coordinates on the screen
|
|
// This function is called from scoreboard.cpp
|
|
// 1 is returned on success, 0 on failure
|
|
bool draw_led(int value, int x, int y)
|
|
{
|
|
vid_blit(g_led_bmps[value], x, y);
|
|
return true;
|
|
}
|
|
|
|
// Draw overlay digits to the screen
|
|
void draw_overlay_leds(unsigned int values[], int num_digits, int start_x, int y, SDL_Surface *overlay)
|
|
{
|
|
SDL_Rect src, dest;
|
|
|
|
dest.x = start_x;
|
|
dest.y = y;
|
|
dest.w = OVERLAY_LED_WIDTH;
|
|
dest.h = OVERLAY_LED_HEIGHT;
|
|
|
|
src.y = 0;
|
|
src.w = OVERLAY_LED_WIDTH;
|
|
src.h = OVERLAY_LED_HEIGHT;
|
|
|
|
/* Draw the digit(s) */
|
|
for(int i = 0; i < num_digits; i++)
|
|
{
|
|
src.x = values[i] * OVERLAY_LED_WIDTH;
|
|
SDL_BlitSurface(g_other_bmps[B_OVERLAY_LEDS], &src, overlay, &dest);
|
|
dest.x += OVERLAY_LED_WIDTH;
|
|
}
|
|
|
|
dest.x = start_x;
|
|
dest.w = num_digits * OVERLAY_LED_WIDTH;
|
|
SDL_UpdateRects(overlay, 1, &dest);
|
|
}
|
|
|
|
// Draw LDP1450 overlay characters to the screen (added by Brad O.)
|
|
void draw_singleline_LDP1450(char *LDP1450_String, int start_x, int y, SDL_Surface *overlay)
|
|
{
|
|
SDL_Rect src, dest;
|
|
|
|
int i = 0;
|
|
int value = 0;
|
|
int LDP1450_strlen;
|
|
// char s[81]="";
|
|
|
|
dest.x = start_x;
|
|
dest.y = y;
|
|
dest.w = OVERLAY_LDP1450_WIDTH;
|
|
dest.h = OVERLAY_LDP1450_HEIGHT;
|
|
|
|
src.y = 0;
|
|
src.w = OVERLAY_LDP1450_WIDTH;
|
|
src.h = OVERLAY_LDP1450_WIDTH;
|
|
|
|
LDP1450_strlen = strlen(LDP1450_String);
|
|
|
|
if (!LDP1450_strlen) // if a blank line is sent, we must blank out the entire line
|
|
{
|
|
strcpy(LDP1450_String," ");
|
|
LDP1450_strlen = strlen(LDP1450_String);
|
|
}
|
|
else
|
|
{
|
|
if (LDP1450_strlen <= 11) // pad end of string with spaces (in case previous line was not cleared)
|
|
{
|
|
for (i=LDP1450_strlen; i<=11; i++)
|
|
LDP1450_String[i] = 32;
|
|
LDP1450_strlen = strlen(LDP1450_String);
|
|
}
|
|
}
|
|
|
|
for (i=0; i<LDP1450_strlen; i++)
|
|
{
|
|
value = LDP1450_String[i];
|
|
|
|
if (value >= 0x26 && value <= 0x39) // numbers and symbols
|
|
value -= 0x25;
|
|
else if (value >= 0x41 && value <= 0x5a) // alpha
|
|
value -= 0x2a;
|
|
else if (value == 0x13) // special LDP-1450 character (inversed space)
|
|
value = 0x32;
|
|
else
|
|
value = 0x31; // if not a number, symbol, or alpha, recognize as a space
|
|
|
|
src.x = value * OVERLAY_LDP1450_WIDTH;
|
|
SDL_BlitSurface(g_other_bmps[B_OVERLAY_LDP1450], &src, overlay, &dest);
|
|
|
|
dest.x += OVERLAY_LDP1450_CHARACTER_SPACING;
|
|
}
|
|
dest.x = start_x;
|
|
dest.w = LDP1450_strlen * OVERLAY_LDP1450_CHARACTER_SPACING;
|
|
|
|
// MPO : calling UpdateRects probably isn't necessary and may be harmful
|
|
//SDL_UpdateRects(overlay, 1, &dest);
|
|
}
|
|
|
|
// used to draw non LED stuff like scoreboard text
|
|
// 'which' corresponds to enumerated values
|
|
bool draw_othergfx(int which, int x, int y, bool bSendToScreenBlitter)
|
|
{
|
|
// NOTE : this is drawn to g_screen_blitter, not to g_screen,
|
|
// to be more friendly to our opengl implementation!
|
|
SDL_Surface *srf = g_other_bmps[which];
|
|
SDL_Rect dest;
|
|
dest.x = (short) x;
|
|
dest.y = (short) y;
|
|
dest.w = (unsigned short) srf->w;
|
|
dest.h = (unsigned short) srf->h;
|
|
|
|
// if we should blit this to the screen blitter for later use ...
|
|
if (bSendToScreenBlitter)
|
|
{
|
|
SDL_BlitSurface(srf, NULL, g_screen_blitter, &dest);
|
|
}
|
|
// else blit it now
|
|
else
|
|
{
|
|
vid_blit(g_other_bmps[which], x, y);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// de-allocates all of the .bmps that we have allocated
|
|
void free_bmps()
|
|
{
|
|
|
|
int nuke_index = 0;
|
|
|
|
// get rid of all the LED's
|
|
for (; nuke_index < LED_RANGE; nuke_index++)
|
|
{
|
|
free_one_bmp(g_led_bmps[nuke_index]);
|
|
}
|
|
for (nuke_index = 0; nuke_index < B_EMPTY; nuke_index++)
|
|
{
|
|
// check to make sure it exists before we try to free
|
|
if (g_other_bmps[nuke_index])
|
|
{
|
|
free_one_bmp(g_other_bmps[nuke_index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void free_one_bmp(SDL_Surface *candidate)
|
|
{
|
|
|
|
SDL_FreeSurface(candidate);
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
SDL_Surface *get_screen()
|
|
{
|
|
return g_screen;
|
|
}
|
|
|
|
SDL_Surface *get_screen_blitter()
|
|
{
|
|
return g_screen_blitter;
|
|
}
|
|
|
|
int get_console_initialized()
|
|
{
|
|
return g_console_initialized;
|
|
}
|
|
|
|
bool get_fullscreen()
|
|
{
|
|
return g_fullscreen;
|
|
}
|
|
|
|
// sets our g_fullscreen bool (determines whether will be in fullscreen mode or not)
|
|
void set_fullscreen(bool value)
|
|
{
|
|
g_fullscreen = value;
|
|
}
|
|
|
|
// by RDG2010
|
|
bool get_fakefullscreen()
|
|
{
|
|
return g_fakefullscreen;
|
|
}
|
|
|
|
void set_fakefullscreen(bool value)
|
|
{
|
|
g_fakefullscreen = value;
|
|
}
|
|
|
|
int get_scalefactor()
|
|
{
|
|
return g_scalefactor;
|
|
}
|
|
void set_scalefactor(int value)
|
|
{
|
|
if (value > 100 || value < 50) // Validating in case user inputs crazy values.
|
|
{
|
|
printline("Invalid scale value. Ignoring -scalefactor parameter.");
|
|
g_scalefactor = 100;
|
|
|
|
} else { g_scalefactor = value; }
|
|
}
|
|
|
|
void set_rotate_degrees(float fDegrees)
|
|
{
|
|
g_fRotateDegrees = fDegrees;
|
|
}
|
|
|
|
void set_sboverlay_characterset(int value)
|
|
{
|
|
sboverlay_characterset = value;
|
|
}
|
|
|
|
// returns video width
|
|
Uint16 get_video_width()
|
|
{
|
|
return g_vid_width;
|
|
}
|
|
|
|
// sets g_vid_width
|
|
void set_video_width(Uint16 width)
|
|
{
|
|
// Let the user specify whatever width s/he wants (and suffer the consequences)
|
|
// We need to support arbitrary resolution to accomodate stuff like screen rotation
|
|
g_vid_width = width;
|
|
}
|
|
|
|
// returns video height
|
|
Uint16 get_video_height()
|
|
{
|
|
return g_vid_height;
|
|
}
|
|
|
|
// sets g_vid_height
|
|
void set_video_height(Uint16 height)
|
|
{
|
|
// Let the user specify whatever height s/he wants (and suffer the consequences)
|
|
// We need to support arbitrary resolution to accomodate stuff like screen rotation
|
|
g_vid_height = height;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// converts the SDL_Overlay to a BMP file
|
|
// ASSUMES OVERLAY IS ALREADY LOCKED!!!
|
|
void take_screenshot(SDL_Overlay *yuvimage)
|
|
{
|
|
SDL_Color cur_color = { 0 };
|
|
bool bSaveYUV = false;
|
|
|
|
#ifdef DEBUG
|
|
// in debug mode, save the YUV stuff too
|
|
bSaveYUV = true;
|
|
#endif // DEBUG
|
|
|
|
SDL_Surface *rgbimage = SDL_CreateRGBSurface(SDL_SWSURFACE, yuvimage->w, yuvimage->h, 32, 0xFF, 0xFF00, 0xFF0000, 0);
|
|
if (rgbimage)
|
|
{
|
|
Uint32 *cur_pixel = (Uint32 *) rgbimage->pixels;
|
|
|
|
// if we're in YV12 format (old)
|
|
if (yuvimage->format == SDL_YV12_OVERLAY)
|
|
{
|
|
Uint8 *Y = yuvimage->pixels[0];
|
|
Uint8 *V = yuvimage->pixels[1];
|
|
Uint8 *U = yuvimage->pixels[2];
|
|
int y_extra = yuvimage->pitches[0] - yuvimage->w;
|
|
int v_extra = yuvimage->pitches[1] - (yuvimage->w / 2);
|
|
int u_extra = yuvimage->pitches[2] - (yuvimage->w / 2);
|
|
|
|
// advance by 2 since the U and V channels are half-sized
|
|
for (int row = 0; row < yuvimage->h; row += 2)
|
|
{
|
|
// advance by 2 since the U and V channels are half-sized
|
|
for (int col = 0; col < yuvimage->w; col += 2)
|
|
{
|
|
// get a 2x2 block of pixels and store them due to YUV structure
|
|
// upper left
|
|
yuv2rgb(&cur_color, *Y, *U, *V);
|
|
cur_pixel[0] = SDL_MapRGB(rgbimage->format, cur_color.r, cur_color.g, cur_color.b);
|
|
|
|
// upper right
|
|
yuv2rgb(&cur_color, *(Y+1), *U, *V);
|
|
cur_pixel[1] = SDL_MapRGB(rgbimage->format, cur_color.r, cur_color.g, cur_color.b);
|
|
|
|
// lower left
|
|
yuv2rgb(&cur_color, *(Y + yuvimage->pitches[0]), *U, *V);
|
|
cur_pixel[0 + rgbimage->w] = SDL_MapRGB(rgbimage->format, cur_color.r, cur_color.g, cur_color.b);
|
|
|
|
// lower right
|
|
yuv2rgb(&cur_color, *(Y + yuvimage->pitches[0] + 1), *U, *V);
|
|
cur_pixel[1 + rgbimage->w] = SDL_MapRGB(rgbimage->format, cur_color.r, cur_color.g, cur_color.b);
|
|
|
|
cur_pixel += 2; // move two pixels over
|
|
Y += 2; // move two Y values over
|
|
U++; // but just 1 U and V
|
|
V++;
|
|
}
|
|
Y += y_extra;
|
|
V += v_extra;
|
|
U += u_extra;
|
|
cur_pixel += rgbimage->w; // move down one row (FIXME: I think this should use pitch)
|
|
// WARNING: the above assumes that the pitch is the width * 4
|
|
|
|
Y += yuvimage->pitches[0]; // move down one line
|
|
}
|
|
}
|
|
else if (yuvimage->format == SDL_YUY2_OVERLAY)
|
|
{
|
|
mpo_io *io = NULL;
|
|
if (bSaveYUV)
|
|
{
|
|
io = mpo_open("surface.YUY2", MPO_OPEN_CREATE);
|
|
}
|
|
|
|
Uint8 *line_ptr = yuvimage->pixels[0];
|
|
for (int row = 0; row < yuvimage->h; row ++)
|
|
{
|
|
// if we're saving to a file, then write the YUY2 line
|
|
if (bSaveYUV)
|
|
{
|
|
mpo_write(line_ptr, yuvimage->w * 2, NULL, io);
|
|
}
|
|
|
|
Uint8 *pixel_ptr = line_ptr;
|
|
// advance by 2 because we're doing 2 pixels at a time
|
|
for (int col = 0; col < yuvimage->w; col += 2)
|
|
{
|
|
// left
|
|
yuv2rgb(&cur_color, *(pixel_ptr), *(pixel_ptr+1), *(pixel_ptr+3));
|
|
cur_pixel[0] = SDL_MapRGB(rgbimage->format, cur_color.r, cur_color.g, cur_color.b);
|
|
|
|
// right
|
|
yuv2rgb(&cur_color, *(pixel_ptr+2), *(pixel_ptr+1), *(pixel_ptr+3));
|
|
cur_pixel[1] = SDL_MapRGB(rgbimage->format, (cur_color.r & 0xFE), (cur_color.g & 0xFE), (cur_color.b & 0xFE));
|
|
|
|
cur_pixel += 2; // move 2 pixels over
|
|
pixel_ptr += 4; // move 4 bytes over
|
|
}
|
|
line_ptr += yuvimage->pitches[0];
|
|
cur_pixel += (rgbimage->pitch - (rgbimage->w*4)) / 4; // this look complicated, but the pitch should be the width * 4 so it's just a precaution
|
|
// NOTE : if the pitch is not a multiple of 4, then we've got problems..
|
|
}
|
|
|
|
if (io)
|
|
{
|
|
mpo_close(io);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printline ("ERROR : unknown YUV format!");
|
|
}
|
|
|
|
// now the RGB image has been created, time to save
|
|
save_screenshot(rgbimage);
|
|
SDL_FreeSurface(rgbimage); // de-allocate surface, as we no longer need it
|
|
|
|
} // end if RGB image
|
|
else
|
|
{
|
|
printline("ERROR: Could not create RGB image to take screenshot with");
|
|
}
|
|
|
|
// if we're in YV12 mode and we should save the YUV stuff, then do so
|
|
if (bSaveYUV && (yuvimage->format == SDL_YV12_OVERLAY))
|
|
{
|
|
// NOW save the Y, U and V channels in separate files
|
|
// Most people won't need or want these files, but I have use of them for testing
|
|
Uint8 *Y = yuvimage->pixels[0];
|
|
Uint8 *V = yuvimage->pixels[1];
|
|
Uint8 *U = yuvimage->pixels[2];
|
|
|
|
struct mpo_io *io = mpo_open("surface.Y", MPO_OPEN_CREATE);
|
|
if (io)
|
|
{
|
|
for (int row = 0; row < yuvimage->h; row++)
|
|
{
|
|
mpo_write(Y, yuvimage->w, NULL, io);
|
|
Y += yuvimage->pitches[0];
|
|
}
|
|
mpo_close(io);
|
|
}
|
|
|
|
io = mpo_open("surface.V", MPO_OPEN_CREATE);
|
|
if (io)
|
|
{
|
|
for (int row = 0; row < (yuvimage->h / 2); row++)
|
|
{
|
|
mpo_write(V, yuvimage->w / 2, NULL, io);
|
|
V += yuvimage->pitches[1];
|
|
}
|
|
mpo_close(io);
|
|
}
|
|
|
|
io = mpo_open("surface.U", MPO_OPEN_CREATE);
|
|
if (io)
|
|
{
|
|
for (int row = 0; row < (yuvimage->h / 2); row++)
|
|
{
|
|
mpo_write(U, yuvimage->w / 2, NULL, io);
|
|
U += yuvimage->pitches[2];
|
|
}
|
|
mpo_close(io);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef USE_OPENGL
|
|
void take_screenshot_GL()
|
|
{
|
|
SDL_Surface *rgbimage = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
g_vid_width, g_vid_height, 32, 0xFF, 0xFF00, 0xFF0000, 0);
|
|
|
|
if (rgbimage)
|
|
{
|
|
unsigned char *bufDst = (unsigned char *) rgbimage->pixels;
|
|
unsigned int uLineLength = g_vid_width << 2;
|
|
|
|
unsigned char *bufTmp = new unsigned char [uLineLength * g_vid_height];
|
|
if (bufTmp)
|
|
{
|
|
// grab current screen
|
|
glReadPixels(0, 0, g_vid_width, g_vid_height, GL_RGBA, GL_UNSIGNED_BYTE, bufTmp);
|
|
|
|
// OpenGL goes bottom to top, and the SDL Surface goes top to bottom,
|
|
// so we have to flip the image.
|
|
for (unsigned int uLine = 0; uLine < g_vid_height; ++uLine)
|
|
{
|
|
unsigned char *u8Dst = bufDst + (uLine * uLineLength);
|
|
unsigned char *u8Src = bufTmp + ((g_vid_height - uLine - 1) * uLineLength);
|
|
|
|
memcpy(u8Dst, u8Src, (g_vid_width << 2));
|
|
}
|
|
|
|
// now the RGB image has been created, time to save
|
|
save_screenshot(rgbimage);
|
|
|
|
delete [] bufTmp;
|
|
}
|
|
else printline("ERROR: take_screenshot_GL memory allocation failed");
|
|
|
|
SDL_FreeSurface(rgbimage); // de-allocate surface, as we no longer need it
|
|
|
|
} // end if RGB image
|
|
else
|
|
{
|
|
printline("ERROR: Could not create RGB image to take screenshot with");
|
|
}
|
|
}
|
|
#endif // USE_OPENGL
|
|
|
|
// saves an SDL surface to a .BMP file in the screenshots directory
|
|
void save_screenshot(SDL_Surface *shot)
|
|
{
|
|
int screenshot_num = 0;
|
|
char filename[81] = { 0 };
|
|
string fullpath;
|
|
|
|
// search for a filename that does not exist
|
|
for (;;)
|
|
{
|
|
screenshot_num++;
|
|
sprintf(filename, "screen%d.bmp", screenshot_num);
|
|
fullpath = g_homedir.get_screenshot_dir() + filename;
|
|
|
|
// if file does not exist, we'll save a screenshot to that filename
|
|
if (!mpo_file_exists(fullpath.c_str()))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SDL_SaveBMP(shot, fullpath.c_str()) == 0)
|
|
{
|
|
outstr("NOTE: Wrote screenshot to file ");
|
|
printline(filename);
|
|
}
|
|
else
|
|
{
|
|
outstr("ERROR: Could not write screenshot to file ");
|
|
printline(filename);
|
|
}
|
|
}
|
|
|
|
// converts YUV to RGB
|
|
// Use this only when you don't care about speed =]
|
|
// NOTE : it is important for y, u, and v to be signed
|
|
void yuv2rgb(SDL_Color *result, int y, int u, int v)
|
|
{
|
|
// NOTE : Visual C++ 7.0 apparently has a bug
|
|
// in its floating point optimizations because this function
|
|
// will return incorrect results when compiled as a Release
|
|
// Possible workaround: use integer math instead of float? or don't use VC++ 7? hehe
|
|
|
|
int b = (int) (1.164*(y - 16) + 2.018*(u - 128));
|
|
int g = (int) (1.164*(y - 16) - 0.813*(v - 128) - 0.391*(u - 128));
|
|
int r = (int) (1.164*(y - 16) + 1.596*(v - 128));
|
|
|
|
// clamp values (not sure if this is necessary, but we aren't worried about speed)
|
|
if (b > 255) b = 255;
|
|
if (b < 0) b = 0;
|
|
if (g > 255) g = 255;
|
|
if (g < 0) g = 0;
|
|
if (r > 255) r = 255;
|
|
if (r < 0) r = 0;
|
|
|
|
result->r = (unsigned char) r;
|
|
result->g = (unsigned char) g;
|
|
result->b = (unsigned char) b;
|
|
}
|
|
|
|
void draw_string(const char* t, int col, int row, SDL_Surface* overlay)
|
|
{
|
|
SDL_Rect dest;
|
|
|
|
dest.x = (short) ((col*6));
|
|
dest.y = (short) ((row*13));
|
|
dest.w = (unsigned short) (6 * strlen(t)); // width of rectangle area to draw (width of font * length of string)
|
|
dest.h = 13; // height of area (height of font)
|
|
|
|
SDL_FillRect(overlay, &dest, 0); // erase anything at our destination before we print new text
|
|
SDLDrawText(t, overlay, FONT_SMALL, dest.x, dest.y);
|
|
SDL_UpdateRects(overlay, 1, &dest);
|
|
}
|
|
|
|
// toggles fullscreen mode
|
|
void vid_toggle_fullscreen()
|
|
{
|
|
// Commented out because it creates major problems with YUV overlays and causing segfaults..
|
|
// The real way to toggle fullscreen is to kill overlay, kill surface, make surface, make overlay.
|
|
/*
|
|
g_screen = SDL_SetVideoMode(g_screen->w,
|
|
g_screen->h,
|
|
g_screen->format->BitsPerPixel,
|
|
g_screen->flags ^ SDL_FULLSCREEN);
|
|
*/
|
|
}
|
|
|
|
// NOTE : put into a separate function to make autotesting easier
|
|
void set_yuv_hwaccel(bool enabled)
|
|
{
|
|
const char *val = "0";
|
|
if (enabled) val = "1";
|
|
#ifdef WIN32
|
|
SetEnvironmentVariable("SDL_VIDEO_YUV_HWACCEL", val);
|
|
string sEnv = "SDL_VIDEO_YUV_HWACCEL=";
|
|
sEnv += val;
|
|
putenv(sEnv.c_str());
|
|
#else
|
|
setenv("SDL_VIDEO_YUV_HWACCEL", val, 1);
|
|
#endif
|
|
}
|
|
|
|
bool get_yuv_hwaccel()
|
|
{
|
|
bool result = true; // it is enabled by default
|
|
#ifdef WIN32
|
|
char buf[30];
|
|
ZeroMemory(buf, sizeof(buf));
|
|
DWORD res = GetEnvironmentVariable("SDL_VIDEO_YUV_HWACCEL", buf, sizeof(buf));
|
|
if (buf[0] == '0') result = false;
|
|
#else
|
|
char *hw_env = getenv("SDL_VIDEO_YUV_HWACCEL");
|
|
|
|
// if HW acceleration has been disabled
|
|
if (hw_env && (hw_env[0] == '0')) result = false;
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
void set_force_aspect_ratio(bool bEnabled)
|
|
{
|
|
g_bForceAspectRatio = bEnabled;
|
|
}
|
|
|
|
bool get_force_aspect_ratio()
|
|
{
|
|
return g_bForceAspectRatio;
|
|
}
|
|
|
|
#ifdef USE_OPENGL
|
|
void set_use_opengl(bool enabled)
|
|
{
|
|
g_bUseOpenGL = enabled;
|
|
}
|
|
|
|
bool get_use_opengl()
|
|
{
|
|
return g_bUseOpenGL;
|
|
}
|
|
|
|
#endif // USE_OPENGL
|
|
|