initial commit

This commit is contained in:
R-type
2015-12-14 14:00:35 +01:00
commit 5a96c0ca66
377 changed files with 149124 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
/*
* sdl/init.c - SDL library specific port code - initialisation routines
*
* Copyright (c) 2012 Tomasz Krasuski
* Copyright (C) 2012 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <SDL.h>
#include "sdl/init.h"
#include "atari.h"
#include "log.h"
#include "platform.h"
int SDL_INIT_Initialise(void)
{
if (SDL_Init(0) != 0) {
Log_print("SDL_Init FAILED: %s", SDL_GetError());
Log_flushlog();
return FALSE;
}
atexit(SDL_Quit);
return TRUE;
}
void SDL_INIT_Exit(void)
{
SDL_Quit();
}
double PLATFORM_Time(void)
{
return SDL_GetTicks() * 1e-3;
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef SDL_INIT_H_
#define SDL_INIT_H_
int SDL_INIT_Initialise(void);
void SDL_INIT_Exit(void);
#endif /* SDL_INIT_H_ */
File diff suppressed because it is too large Load Diff
+16
View File
@@ -0,0 +1,16 @@
#ifndef SDL_INPUT_H_
#define SDL_INPUT_H_
#include <stdio.h>
int SDL_INPUT_ReadConfig(char *option, char *parameters);
void SDL_INPUT_WriteConfig(FILE *fp);
int SDL_INPUT_Initialise(int *argc, char *argv[]);
void SDL_INPUT_Exit(void);
/* Restarts input after e.g. exiting the console monitor. */
void SDL_INPUT_Restart(void);
void SDL_INPUT_Mouse(void);
#endif /* SDL_INPUT_H_ */
+202
View File
@@ -0,0 +1,202 @@
/*
* sdl/main.c - SDL library specific port code - main interface
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Thanks to David Olofson for scaling tips!
TODO:
- implement all Atari800 parameters
- turn off fullscreen when error happen
*/
#include "config.h"
#include <SDL.h>
#include <stdio.h>
#include <string.h>
/* Atari800 includes */
#include "atari.h"
#include "../input.h"
#include "log.h"
#include "monitor.h"
#include "platform.h"
#ifdef SOUND
#include "../sound.h"
#endif
#ifdef USE_UI_BASIC_ONSCREEN_KEYBOARD
#include "akey.h"
#include "ui_basic.h"
#endif
#include "videomode.h"
#include "sdl/video.h"
#include "sdl/input.h"
int PLATFORM_Configure(char *option, char *parameters)
{
return SDL_VIDEO_ReadConfig(option, parameters) ||
SDL_INPUT_ReadConfig(option, parameters);
}
void PLATFORM_ConfigSave(FILE *fp)
{
SDL_VIDEO_WriteConfig(fp);
SDL_INPUT_WriteConfig(fp);
}
int PLATFORM_Initialise(int *argc, char *argv[])
{
int i, j;
int help_only = FALSE;
for (i = j = 1; i < *argc; i++) {
if (strcmp(argv[i], "-help") == 0) {
help_only = TRUE;
}
argv[j++] = argv[i];
}
*argc = j;
if (!help_only) {
i = SDL_INIT_JOYSTICK
#if HAVE_WINDOWS_H
/* Timers are used to avoid one Windows 7 glitch, see src/sdl/input.c */
| SDL_INIT_TIMER
#endif /* HAVE_WINDOWS_H */
;
if (SDL_InitSubSystem(i) != 0) {
Log_print("SDL_InitSubSystem FAILED: %s", SDL_GetError());
Log_flushlog();
exit(-1);
}
}
if (!SDL_VIDEO_Initialise(argc, argv)
#ifdef SOUND
|| !Sound_Initialise(argc, argv)
#endif
|| !SDL_INPUT_Initialise(argc, argv))
return FALSE;
return TRUE;
}
int PLATFORM_Exit(int run_monitor)
{
SDL_INPUT_Exit();
/* If the SDL window was left not closed, it would be unusable and hanging
for the time the monitor is active. Also, with SDL_VIDEODRIVER=directx all
keyboard presses in console would be still fetched by the SDL window after
leaving the monitor. To avoid the problems, close the video subsystem. */
SDL_VIDEO_Exit();
Log_flushlog();
if (run_monitor) {
#ifdef SOUND
Sound_Pause();
#endif
if (MONITOR_Run()) {
/* Reinitialise the SDL subsystem. */
#ifdef MONITOR_BREAK
if (!MONITOR_break_step) /*Do not initialise videomode when stepping through code */
#endif
{
SDL_VIDEO_InitSDL();
SDL_INPUT_Restart();
/* This call reopens the SDL window. */
VIDEOMODE_Update();
}
#ifdef SOUND
Sound_Continue();
#endif
return 1;
}
}
return 0;
}
#if HAVE_WINDOWS_H
static BOOL CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
case CTRL_CLOSE_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
/* Perform a normal exit. */
Atari800_Exit(FALSE);
case CTRL_C_EVENT:
/* Ctrl+C is handled in atari.c */
return TRUE;
default:
return FALSE;
}
}
#endif /* HAVE_WINDOWS_H */
int main(int argc, char **argv)
{
#if HAVE_WINDOWS_H
/* Handle Windows console signals myself. If not, then closing
the console window would cause emulator crash due to the sound
subsystem being active. */
if(!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
Log_print("ERROR: Could not set console control handler");
return 1;
}
#endif /* HAVE_WINDOWS_H */
/* initialise Atari800 core */
if (!Atari800_Initialise(&argc, argv))
return 3;
/* main loop */
for (;;) {
INPUT_key_code = PLATFORM_Keyboard();
#ifdef USE_UI_BASIC_ONSCREEN_KEYBOARD
if (INPUT_key_code == AKEY_KEYB) {
Sound_Pause();
UI_BASIC_in_kbui = TRUE;
INPUT_key_code = UI_BASIC_OnScreenKeyboard(NULL, 0);
UI_BASIC_in_kbui = FALSE;
switch (INPUT_key_code) {
case AKEY_OPTION: INPUT_key_consol &= (~INPUT_CONSOL_OPTION); break;
case AKEY_SELECT: INPUT_key_consol &= (~INPUT_CONSOL_SELECT); break;
case AKEY_START: INPUT_key_consol &= (~INPUT_CONSOL_START); break;
}
Sound_Continue();
}
#endif
SDL_INPUT_Mouse();
Atari800_Frame();
if (Atari800_display_screen)
PLATFORM_DisplayScreen();
}
}
/*
vim:ts=4:sw=4:
*/
+87
View File
@@ -0,0 +1,87 @@
/*
* sdl/palette.c - SDL library specific port code - table of display palettes
*
* Copyright (c) 2010 Tomasz Krasuski
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <SDL.h>
#include "sdl/palette.h"
#include "af80.h"
#include "bit3.h"
#include "config.h"
#include "colours.h"
#include "videomode.h"
SDL_PALETTE_tab_t const SDL_PALETTE_tab[VIDEOMODE_MODE_SIZE] = {
{ Colours_table, 256 } /* Standard display */
#if NTSC_FILTER
,{ Colours_table, 256 } /* NTSC filter */
#endif
#ifdef XEP80_EMULATION
,{ Colours_table, 256 } /* XEP80 also uses the standard palette */
#endif
#ifdef PBI_PROTO80
,{ Colours_table, 256 } /* So does PBI Proto80 */
#endif
#ifdef AF80
,{ AF80_palette, 16 } /* AF80 */
#endif
#ifdef BIT3
,{ BIT3_palette, 2 } /* BIT3 */
#endif
};
SDL_PALETTE_buffer_t SDL_PALETTE_buffer;
void SDL_PALETTE_Calculate32_A8R8G8B8(void *dest, int const *palette, int size)
{
int i;
for (i = 0; i < size; i++) {
((Uint32 *)dest)[i] = 0xff000000 | palette[i];
}
}
void SDL_PALETTE_Calculate32_B8G8R8A8(void *dest, int const *palette, int size)
{
int i;
for (i = 0; i < size; i++) {
int rgb = palette[i];
((Uint32 *)dest)[i] = 0xff | ((rgb & 0x00ff0000) >> 8) | ((rgb & 0x0000ff00) << 8) | ((rgb & 0x000000ff) << 24);
}
}
void SDL_PALETTE_Calculate16_R5G6B5(void *dest, int const *palette, int size)
{
int i;
for (i = 0; i < size; i++) {
int rgb = palette[i];
((Uint16 *)dest)[i] = ((rgb & 0x00f80000) >> 8) | ((rgb & 0x0000fc00) >> 5) | ((rgb & 0x000000f8) >> 3);
}
}
void SDL_PALETTE_Calculate16_B5G6R5(void *dest, int const *palette, int size)
{
int i;
for (i = 0; i < size; i++) {
int rgb = palette[i];
((Uint16 *)dest)[i] = ((rgb & 0x00f80000) >> 19) | ((rgb & 0x0000fc00) >> 5) | ((rgb & 0x000000f8) << 8);
}
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef SDL_PALETTE_H_
#define SDL_PALETTE_H_
#include <SDL.h>
#include "videomode.h"
typedef struct SDL_PALETTE_tab_t {
int *palette;
int size;
} SDL_PALETTE_tab_t;
/* Contains pointers to palettes used by various display modes, and their sizes.
The table is indexed by a VIDEOMODE_MODE_t value. */
extern SDL_PALETTE_tab_t const SDL_PALETTE_tab[VIDEOMODE_MODE_SIZE];
typedef union SDL_PALETTE_buffer_t {
Uint16 bpp16[256]; /* 16-bit palette */
Uint32 bpp32[256]; /* 32-bit palette */
} SDL_PALETTE_buffer_t;
/* Holds all palette values for the currently-used pixel format (BGR, RGB,
ARGB etc.) */
extern SDL_PALETTE_buffer_t SDL_PALETTE_buffer;
void SDL_PALETTE_Calculate32_A8R8G8B8(void *dest, int const *palette, int size);
void SDL_PALETTE_Calculate32_B8G8R8A8(void *dest, int const *palette, int size);
void SDL_PALETTE_Calculate16_R5G6B5(void *dest, int const *palette, int size);
void SDL_PALETTE_Calculate16_B5G6R5(void *dest, int const *palette, int size);
#endif /* SDL_PALETTE_H_ */
+95
View File
@@ -0,0 +1,95 @@
/*
* sdl/sound.c - SDL library specific port code - sound output
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2013 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <SDL.h>
#include "atari.h"
#include "log.h"
#include "platform.h"
#include "sound.h"
static void SoundCallback(void *userdata, Uint8 *stream, int len)
{
Sound_Callback(stream, len);
}
int PLATFORM_SoundSetup(Sound_setup_t *setup)
{
SDL_AudioSpec desired;
if (Sound_enabled)
SDL_CloseAudio();
else if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
Log_print("SDL_INIT_AUDIO FAILED: %s", SDL_GetError());
return FALSE;
}
desired.freq = setup->freq;
desired.format = setup->sample_size == 2 ? AUDIO_S16SYS : AUDIO_U8;
desired.channels = setup->channels;
if (setup->buffer_frames == 0)
/* Set buffer_frames automatically. */
setup->buffer_frames = setup->freq / 50;
setup->buffer_frames = Sound_NextPow2(setup->buffer_frames);
desired.samples = setup->buffer_frames;
desired.callback = SoundCallback;
desired.userdata = NULL;
if (SDL_OpenAudio(&desired, NULL) < 0) {
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return FALSE;
}
setup->buffer_frames = desired.samples;
return TRUE;
}
void PLATFORM_SoundExit(void)
{
SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
void PLATFORM_SoundPause(void)
{
SDL_PauseAudio(1);
}
void PLATFORM_SoundContinue(void)
{
SDL_PauseAudio(0);
}
void PLATFORM_SoundLock(void)
{
SDL_LockAudio();
}
void PLATFORM_SoundUnlock(void)
{
SDL_UnlockAudio();
}
+924
View File
@@ -0,0 +1,924 @@
/*
* sdl/video.c - SDL library specific port code - video display
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <SDL.h>
#include "af80.h"
#include "bit3.h"
#include "artifact.h"
#include "atari.h"
#include "colours.h"
#include "config.h"
#include "filter_ntsc.h"
#include "log.h"
#ifdef PAL_BLENDING
#include "pal_blending.h"
#endif /* PAL_BLENDING */
#include "pbi_proto80.h"
#include "platform.h"
#include "screen.h"
#include "util.h"
#include "videomode.h"
#include "xep80.h"
#include "sdl/input.h"
#include "sdl/palette.h"
#include "sdl/video.h"
#include "sdl/video_sw.h"
#if HAVE_OPENGL
#include "sdl/video_gl.h"
#endif
/* This value must be set during initialisation, because on Windows BPP
autodetection works only before the first call to SDL_SetVideoMode(). */
int SDL_VIDEO_native_bpp;
int SDL_VIDEO_scanlines_percentage = 5;
int SDL_VIDEO_interpolate_scanlines = TRUE;
int SDL_VIDEO_width;
int SDL_VIDEO_height;
VIDEOMODE_MODE_t SDL_VIDEO_current_display_mode = VIDEOMODE_MODE_NORMAL;
SDL_Surface *SDL_VIDEO_screen = NULL;
/* Desktop screen resolution is stored here on initialisation. */
static VIDEOMODE_resolution_t desktop_resolution;
#if HAVE_OPENGL
int SDL_VIDEO_opengl_available;
int SDL_VIDEO_opengl = FALSE;
/* Was OpenGL active previously? */
static int currently_opengl = FALSE;
#endif
int SDL_VIDEO_vsync = FALSE;
int SDL_VIDEO_vsync_available;
static int window_maximised = FALSE;
#if HAVE_WINDOWS_H
/* Contains TRUE if the user chose a video backend by setting
the SDL_VIDEODRIVER environment variable. */
static int user_video_driver = FALSE;
#endif /* HAVE_WINDOWS_H */
void SDL_VIDEO_UpdatePaletteLookup(VIDEOMODE_MODE_t mode, int bpp_32)
{
#ifdef PAL_BLENDING
if (mode == VIDEOMODE_MODE_NORMAL && ARTIFACT_mode == ARTIFACT_PAL_BLEND)
PAL_BLENDING_UpdateLookup();
else
#endif /* PAL_BLENDING */
#ifdef NTSC_FILTER
if (mode != VIDEOMODE_MODE_NTSC_FILTER)
#endif
{
void *dest;
if (bpp_32)
dest = SDL_PALETTE_buffer.bpp32;
else
dest = SDL_PALETTE_buffer.bpp16;
PLATFORM_MapRGB(dest, SDL_PALETTE_tab[mode].palette, SDL_PALETTE_tab[mode].size);
}
}
void PLATFORM_PaletteUpdate(void)
{
#ifdef NTSC_FILTER
if (SDL_VIDEO_current_display_mode == VIDEOMODE_MODE_NTSC_FILTER)
FILTER_NTSC_Update(FILTER_NTSC_emu);
else
#endif
{
#if HAVE_OPENGL
if (SDL_VIDEO_opengl)
SDL_VIDEO_GL_PaletteUpdate();
else
#endif
SDL_VIDEO_SW_PaletteUpdate();
}
}
void PLATFORM_GetPixelFormat(PLATFORM_pixel_format_t *format)
{
#if HAVE_OPENGL
if (SDL_VIDEO_opengl)
SDL_VIDEO_GL_GetPixelFormat(format);
else
#endif
SDL_VIDEO_SW_GetPixelFormat(format);
}
void PLATFORM_MapRGB(void *dest, int const *palette, int size)
{
#if HAVE_OPENGL
if (SDL_VIDEO_opengl)
SDL_VIDEO_GL_MapRGB(dest, palette, size);
else
#endif
SDL_VIDEO_SW_MapRGB(dest, palette, size);
}
#ifdef NTSC_FILTER
static void UpdateNtscFilter(VIDEOMODE_MODE_t mode)
{
if (mode != VIDEOMODE_MODE_NTSC_FILTER && FILTER_NTSC_emu != NULL) {
/* Turning filter off */
FILTER_NTSC_Delete(FILTER_NTSC_emu);
FILTER_NTSC_emu = NULL;
#if HAVE_OPENGL
if (SDL_VIDEO_opengl)
SDL_VIDEO_GL_PaletteUpdate();
else
#endif
SDL_VIDEO_SW_PaletteUpdate();
}
else if (mode == VIDEOMODE_MODE_NTSC_FILTER && FILTER_NTSC_emu == NULL) {
/* Turning filter on */
FILTER_NTSC_emu = FILTER_NTSC_New();
FILTER_NTSC_Update(FILTER_NTSC_emu);
}
}
#endif
void PLATFORM_SetVideoMode(VIDEOMODE_resolution_t const *res, int windowed, VIDEOMODE_MODE_t mode, int rotate90)
{
/* In SDL there's really no way to determine if a window is maximised. So we use a method
that's not 100% sure: if we notice, that the windows's horizontal size equals desktop
resolution, then we assume that the window is maximised. This works at least on Windows
and Linux/KDE. */
window_maximised = windowed && res->width == desktop_resolution.width;
#if HAVE_WINDOWS_H
/* On Windows, choose Windib or DirectX backend when switching between
fullscreen<->windowed. */
if (!user_video_driver &&
SDL_VIDEO_screen != NULL &&
((SDL_VIDEO_screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) == windowed) {
if (windowed)
SDL_putenv("SDL_VIDEODRIVER=windib");
else
SDL_putenv("SDL_VIDEODRIVER=directx");
/* SDL_VIDEODRIVER is only used when initialising the video subsystem. */
SDL_VIDEO_ReinitSDL();
}
#if HAVE_OPENGL
/* Reinitialise the video subsystem when switching between software<->OpenGL
to avoid various SDL glitches and segfaults that might appear depending on
the type of graphics hardware. */
else if (SDL_VIDEO_screen != NULL && SDL_VIDEO_opengl != currently_opengl)
SDL_VIDEO_ReinitSDL();
#endif /* HAVE_OPENGL */
#endif /* HAVE_WINDOWS_H */
#if HAVE_OPENGL
if (SDL_VIDEO_opengl) {
if (!currently_opengl)
SDL_VIDEO_screen = NULL;
/* Switching to OpenGL can fail when the host machine doesn't
support it. If so, revert to software mode. */
if (!SDL_VIDEO_GL_SetVideoMode(res, windowed, mode, rotate90)) {
SDL_VIDEO_GL_Cleanup();
SDL_VIDEO_screen = NULL;
SDL_VIDEO_opengl = SDL_VIDEO_opengl_available = FALSE;
VIDEOMODE_Update();
}
} else {
if (currently_opengl) {
SDL_VIDEO_GL_Cleanup();
SDL_VIDEO_screen = NULL;
}
SDL_VIDEO_SW_SetVideoMode(res, windowed, mode, rotate90);
}
currently_opengl = SDL_VIDEO_opengl;
#else
SDL_VIDEO_SW_SetVideoMode(res, windowed, mode, rotate90);
#endif
SDL_VIDEO_current_display_mode = mode;
#ifdef NTSC_FILTER
UpdateNtscFilter(mode);
#endif
PLATFORM_DisplayScreen();
/* For unknown reason (maybe window manager-related), when SDL_SetVideoMode
is called twice without calling SDL_PollEvent in between, SDL may throw
an SDL_VIDEORESIZE event. (Happens on KDE4 in windowed mode during
initialisation of the XEP80 handler (TV system = PAL), when it switches
between 60Hz and 50Hz modes rapidly). If this event was processed, it
would cause another screen resize, resulting in invalid window size. To
avoid the glitch, we ignore all pending SDL_VIDEORESIZE events after
each screen resize. */
for (;;) {
SDL_Event event;
int found = FALSE;
SDL_PumpEvents();
while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_VIDEORESIZE)) > 0)
found = TRUE;
if (!found)
break;
}
}
VIDEOMODE_resolution_t *PLATFORM_AvailableResolutions(unsigned int *size)
{
SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
VIDEOMODE_resolution_t *resolutions;
unsigned int num_modes;
unsigned int i;
if (modes == (SDL_Rect**)0)
return NULL;
if (modes == (SDL_Rect**)-1) {
resolutions = (VIDEOMODE_resolution_t *)Util_malloc(sizeof(VIDEOMODE_resolution_t));
resolutions[0].width = 336;
resolutions[0].height = 240;
*size = 1;
return resolutions;
}
/* Determine number of available modes. */
for (num_modes = 0; modes[num_modes] != NULL; ++num_modes);
resolutions = (VIDEOMODE_resolution_t *)Util_malloc(num_modes * sizeof(VIDEOMODE_resolution_t));
for (i = 0; i < num_modes; i++) {
resolutions[i].width = modes[i]->w;
resolutions[i].height = modes[i]->h;
}
*size = num_modes;
return resolutions;
}
VIDEOMODE_resolution_t *PLATFORM_DesktopResolution(void)
{
/* FIXME: This function should always return the current desktop
resolution, not a resolution stored on initialisation. */
return &desktop_resolution;
}
int PLATFORM_SupportsVideomode(VIDEOMODE_MODE_t mode, int stretch, int rotate90)
{
#if HAVE_OPENGL
if (SDL_VIDEO_opengl)
return SDL_VIDEO_GL_SupportsVideomode(mode, stretch, rotate90);
else
#endif
return SDL_VIDEO_SW_SupportsVideomode(mode, stretch, rotate90);
}
int PLATFORM_WindowMaximised(void)
{
return window_maximised;
}
void PLATFORM_DisplayScreen(void)
{
#if HAVE_OPENGL
if (SDL_VIDEO_opengl)
SDL_VIDEO_GL_DisplayScreen();
else
#endif
SDL_VIDEO_SW_DisplayScreen();
}
int SDL_VIDEO_ReadConfig(char *option, char *parameters)
{
if (strcmp(option, "SCANLINES_PERCENTAGE") == 0) {
int value = Util_sscandec(parameters);
if (value < 0 || value > 100)
return FALSE;
else {
SDL_VIDEO_scanlines_percentage = value;
}
}
else if (strcmp(option, "INTERPOLATE_SCANLINES") == 0)
return (SDL_VIDEO_interpolate_scanlines = Util_sscanbool(parameters)) != -1;
else if (strcmp(option, "VIDEO_VSYNC") == 0)
return (SDL_VIDEO_vsync = Util_sscanbool(parameters)) != -1;
#if HAVE_OPENGL
else if (strcmp(option, "VIDEO_ACCEL") == 0)
return (currently_opengl = SDL_VIDEO_opengl = Util_sscanbool(parameters)) != -1;
else if (SDL_VIDEO_GL_ReadConfig(option, parameters)) {
}
#endif /* HAVE_OPENGL */
else if (SDL_VIDEO_SW_ReadConfig(option, parameters)) {
}
else
return FALSE;
return TRUE;
}
void SDL_VIDEO_WriteConfig(FILE *fp)
{
fprintf(fp, "SCANLINES_PERCENTAGE=%d\n", SDL_VIDEO_scanlines_percentage);
fprintf(fp, "INTERPOLATE_SCANLINES=%d\n", SDL_VIDEO_interpolate_scanlines);
fprintf(fp, "VIDEO_VSYNC=%d\n", SDL_VIDEO_vsync);
#if HAVE_OPENGL
fprintf(fp, "VIDEO_ACCEL=%d\n", SDL_VIDEO_opengl);
SDL_VIDEO_GL_WriteConfig(fp);
#endif
SDL_VIDEO_SW_WriteConfig(fp);
}
void SDL_VIDEO_InitSDL(void)
{
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
Log_print("SDL_INIT_VIDEO FAILED: %s", SDL_GetError());
Log_flushlog();
exit(-1);
}
/* SDL_WM_SetIcon("/usr/local/atari800/atarixe.ICO"), NULL); */
SDL_WM_SetCaption(Atari800_TITLE, "Atari800");
/* Get the desktop resolution */
{
SDL_VideoInfo const * const info = SDL_GetVideoInfo();
desktop_resolution.width = info->current_w;
desktop_resolution.height = info->current_h;
SDL_VIDEO_native_bpp = info->vfmt->BitsPerPixel;
}
#if HAVE_OPENGL
SDL_VIDEO_GL_InitSDL();
if (!SDL_VIDEO_opengl_available)
currently_opengl = SDL_VIDEO_opengl = FALSE;
#endif
SDL_EnableUNICODE(1);
}
void SDL_VIDEO_QuitSDL(void)
{
if (SDL_VIDEO_screen != NULL) {
#if HAVE_OPENGL
if (currently_opengl)
SDL_VIDEO_GL_Cleanup();
#endif
SDL_VIDEO_screen = NULL;
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
}
void SDL_VIDEO_ReinitSDL(void)
{
SDL_VIDEO_QuitSDL();
/* At this moment the SDL window gets destroyed but for any pressed key no SDL_KEY_UP
event is received. We have to flush the input state manually. */
SDL_INPUT_Restart();
SDL_VIDEO_InitSDL();
}
int SDL_VIDEO_Initialise(int *argc, char *argv[])
{
int i, j;
int help_only = FALSE;
for (i = j = 1; i < *argc; i++) {
int i_a = (i + 1 < *argc); /* is argument available? */
int a_m = FALSE; /* error, argument missing! */
if (strcmp(argv[i], "-scanlines") == 0) {
if (i_a) {
SDL_VIDEO_scanlines_percentage = Util_sscandec(argv[++i]);
}
else a_m = TRUE;
}
else if (strcmp(argv[i], "-scanlinesint") == 0)
SDL_VIDEO_interpolate_scanlines = TRUE;
else if (strcmp(argv[i], "-no-scanlinesint") == 0)
SDL_VIDEO_interpolate_scanlines = FALSE;
#if HAVE_OPENGL
else if (strcmp(argv[i], "-video-accel") == 0)
currently_opengl = SDL_VIDEO_opengl = TRUE;
else if (strcmp(argv[i], "-no-video-accel") == 0)
currently_opengl = SDL_VIDEO_opengl = FALSE;
#endif /* HAVE_OPENGL */
else if (strcmp(argv[i], "-vsync") == 0)
SDL_VIDEO_vsync = TRUE;
else if (strcmp(argv[i], "-no-vsync") == 0)
SDL_VIDEO_vsync = FALSE;
else {
if (strcmp(argv[i], "-help") == 0) {
help_only = TRUE;
Log_print("\t-scanlines Set visibility of scanlines (0..100)");
Log_print("\t-scanlinesint Enable scanlines interpolation");
Log_print("\t-no-scanlinesint Disable scanlines interpolation");
#if HAVE_OPENGL
Log_print("\t-video-accel Use hardware video acceleration");
Log_print("\t-no-video-accel Don't use hardware video acceleration");
#endif /* HAVE_OPENGL */
Log_print("\t-vsync Synchronize display to vertical retrace");
Log_print("\t-no-vsync Don't synchronize display to vertical retrace");
}
argv[j++] = argv[i];
}
if (a_m) {
Log_print("Missing argument for '%s'", argv[i]);
return FALSE;
}
}
*argc = j;
if (!SDL_VIDEO_SW_Initialise(argc, argv)
#if HAVE_OPENGL
|| !SDL_VIDEO_GL_Initialise(argc, argv)
#endif
)
return FALSE;
if (!help_only) {
#ifdef HAVE_WINDOWS_H
/* On Windows the DirectX SDL backend is glitchy in windowed modes, but allows
for vertical synchronisation in fullscreen modes. Unless the user specified
his own backend, use DirectX in fullscreen modes and Windib in windowed modes. */
if (SDL_getenv("SDL_VIDEODRIVER") != NULL)
user_video_driver = TRUE;
else if (VIDEOMODE_windowed)
SDL_putenv("SDL_VIDEODRIVER=windib");
else
SDL_putenv("SDL_VIDEODRIVER=directx");
#endif /* HAVE_WINDOWS_H */
SDL_VIDEO_InitSDL();
}
return TRUE;
}
void SDL_VIDEO_Exit(void)
{
SDL_VIDEO_QuitSDL();
#ifdef NTSC_FILTER
if (FILTER_NTSC_emu)
#endif
{
/* Turning filter off */
FILTER_NTSC_Delete(FILTER_NTSC_emu);
FILTER_NTSC_emu = NULL;
}
}
void SDL_VIDEO_BlitNormal8(Uint32 *dest, Uint8 *src, int pitch, int width, int height)
{
register Uint32 *start32 = dest;
while (height > 0) {
memcpy(start32, src, width);
src += Screen_WIDTH;
start32 += pitch;
height--;
}
}
void SDL_VIDEO_BlitNormal16(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint16 *palette16)
{
register Uint32 quad;
register Uint32 *start32 = dest;
register Uint8 c;
register int pos;
int width_32;
if (width & 0x01)
width_32 = width + 1;
else
width_32 = width;
while (height > 0) {
pos = width_32;
do {
pos--;
c = src[pos];
quad = palette16[c] << 16;
pos--;
c = src[pos];
quad += palette16[c];
start32[pos >> 1] = quad;
} while (pos > 0);
src += Screen_WIDTH;
start32 += pitch;
height--;
}
}
void SDL_VIDEO_BlitNormal32(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint32 *palette32)
{
register Uint32 quad;
register Uint32 *start32 = dest;
register Uint8 c;
register int pos;
while (height > 0) {
pos = width;
do {
pos--;
c = src[pos];
quad = palette32[c];
start32[pos] = quad;
} while (pos > 0);
src += Screen_WIDTH;
start32 += pitch;
height--;
}
}
void SDL_VIDEO_BlitXEP80_8(Uint32 *dest, Uint8 *src, int pitch, int width, int height)
{
register Uint32 *start32 = dest;
while (height > 0) {
memcpy(start32, src, width);
start32 += pitch;
src += XEP80_SCRN_WIDTH;
height--;
}
}
void SDL_VIDEO_BlitXEP80_16(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint16 *palette16)
{
register Uint32 quad;
register Uint32 *start32 = dest;
register Uint8 c;
register int pos;
int width_32;
if (width & 0x01)
width_32 = width + 1;
else
width_32 = width;
while (height > 0) {
pos = width_32;
do {
pos--;
c = src[pos];
quad = palette16[c] << 16;
pos--;
c = src[pos];
quad += palette16[c];
start32[pos >> 1] = quad;
} while (pos > 0);
src += XEP80_SCRN_WIDTH;
start32 += pitch;
height--;
}
}
void SDL_VIDEO_BlitXEP80_32(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint32 *palette32)
{
register Uint32 quad;
register Uint32 *start32 = dest;
register Uint8 c;
register int pos;
while (height > 0) {
pos = width;
do {
pos--;
c = src[pos];
quad = palette32[c];
start32[pos] = quad;
} while (pos > 0);
src += XEP80_SCRN_WIDTH;
start32 += pitch;
height--;
}
}
void SDL_VIDEO_BlitProto80_8(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line)
{
int skip = pitch - (last_column - first_column)*2;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
register Uint32 quad;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
pixels = PBI_PROTO80_GetPixels(first_line, column);
for (i = 0; i < 2; i++) {
if (pixels & 0x80)
quad = 0x0000000f;
else
quad = 0x00000000;
if (pixels & 0x40)
quad |= 0x00000f00;
if (pixels & 0x20)
quad |= 0x000f0000;
if (pixels & 0x10)
quad |= 0x0f000000;
*start32++ = quad;
pixels <<= 4;
}
}
start32 += skip;
}
}
void SDL_VIDEO_BlitProto80_16(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, Uint16 *palette16)
{
Uint32 const black = (Uint32)palette16[0];
Uint32 const white = (Uint32)palette16[15];
Uint32 const black2 = black << 16;
Uint32 const white2 = white << 16;
int skip = pitch - (last_column - first_column)*4;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
register Uint32 quad;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
pixels = PBI_PROTO80_GetPixels(first_line, column);
for (i = 0; i < 4; i++) {
if (pixels & 0x80)
quad = white;
else
quad = black;
if (pixels & 0x40)
quad |= white2;
else
quad |= black2;
*start32++ = quad;
pixels <<= 2;
}
}
start32 += skip;
}
}
void SDL_VIDEO_BlitProto80_32(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, Uint32 *palette32)
{
Uint32 const black = palette32[0];
Uint32 const white = palette32[15];
int skip = pitch - (last_column - first_column)*8;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
pixels = PBI_PROTO80_GetPixels(first_line, column);
for (i = 0; i < 8; i++) {
if (pixels & 0x80)
*start32++ = white;
else
*start32++ = black;
pixels <<= 1;
}
}
start32 += skip;
}
}
#ifdef AF80
void SDL_VIDEO_BlitAF80_8(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink)
{
int skip = pitch - (last_column - first_column)*2;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
register Uint32 quad;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
int colour;
pixels = AF80_GetPixels(first_line, column, &colour, blink);
for (i = 0; i < 2; i++) {
if (pixels & 0x01)
quad = colour;
else
quad = 0;
if (pixels & 0x02)
quad |= colour << 8;
if (pixels & 0x04)
quad |= colour << 16;
if (pixels & 0x08)
quad |= colour << 24;
*start32++ = quad;
pixels >>= 4;
}
}
start32 += skip;
}
}
void SDL_VIDEO_BlitAF80_16(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint16 *palette16)
{
Uint32 const black = (Uint32)palette16[0];
Uint32 const black2 = black << 16;
int skip = pitch - (last_column - first_column)*4;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
register Uint32 quad;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
int colour;
pixels = AF80_GetPixels(first_line, column, &colour, blink);
for (i = 0; i < 4; i++) {
if (pixels & 0x01)
quad = palette16[colour];
else
quad = black;
if (pixels & 0x02)
quad |= palette16[colour] << 16;
else
quad |= black2;
*start32++ = quad;
pixels >>= 2;
}
}
start32 += skip;
}
}
void SDL_VIDEO_BlitAF80_32(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint32 *palette32)
{
Uint32 const black = palette32[0];
int skip = pitch - (last_column - first_column)*8;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
int colour;
pixels = AF80_GetPixels(first_line, column, &colour, blink);
for (i = 0; i < 8; i++) {
if (pixels & 0x01)
*start32++ = palette32[colour];
else
*start32++ = black;
pixels >>= 1;
}
}
start32 += skip;
}
}
#endif /* AF80 */
#ifdef BIT3
void SDL_VIDEO_BlitBIT3_8(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink)
{
int skip = pitch - (last_column - first_column)*2;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
register Uint32 quad;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
int colour;
pixels = BIT3_GetPixels(first_line, column, &colour, blink);
for (i = 0; i < 2; i++) {
if (pixels & 0x01)
quad = colour;
else
quad = 0;
if (pixels & 0x02)
quad |= colour << 8;
if (pixels & 0x04)
quad |= colour << 16;
if (pixels & 0x08)
quad |= colour << 24;
*start32++ = quad;
pixels >>= 4;
}
}
start32 += skip;
}
}
void SDL_VIDEO_BlitBIT3_16(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint16 *palette16)
{
Uint32 const black = (Uint32)palette16[0];
Uint32 const black2 = black << 16;
int skip = pitch - (last_column - first_column)*4;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
register Uint32 quad;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
int colour;
pixels = BIT3_GetPixels(first_line, column, &colour, blink);
for (i = 0; i < 4; i++) {
if (pixels & 0x01)
quad = palette16[colour];
else
quad = black;
if (pixels & 0x02)
quad |= palette16[colour] << 16;
else
quad |= black2;
*start32++ = quad;
pixels >>= 2;
}
}
start32 += skip;
}
}
void SDL_VIDEO_BlitBIT3_32(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint32 *palette32)
{
Uint32 const black = palette32[0];
int skip = pitch - (last_column - first_column)*8;
register Uint32 *start32 = dest;
unsigned int column;
UBYTE pixels;
for (; first_line < last_line; first_line++) {
for (column = first_column; column < last_column; column++) {
int i;
int colour;
pixels = BIT3_GetPixels(first_line, column, &colour, blink);
for (i = 0; i < 8; i++) {
if (pixels & 0x01)
*start32++ = palette32[colour];
else
*start32++ = black;
pixels >>= 1;
}
}
start32 += skip;
}
}
#endif /* BIT3 */
void SDL_VIDEO_SetScanlinesPercentage(int value)
{
if (value < 0)
value = 0;
else if (value > 100)
value = 100;
SDL_VIDEO_scanlines_percentage = value;
#if HAVE_OPENGL
SDL_VIDEO_GL_ScanlinesPercentageChanged();
#endif /* HAVE_OPENGL */
}
void SDL_VIDEO_SetInterpolateScanlines(int value)
{
SDL_VIDEO_interpolate_scanlines = value;
#if HAVE_OPENGL
SDL_VIDEO_GL_InterpolateScanlinesChanged();
#endif /* HAVE_OPENGL */
}
void SDL_VIDEO_ToggleInterpolateScanlines(void)
{
SDL_VIDEO_SetInterpolateScanlines(!SDL_VIDEO_interpolate_scanlines);
}
#if HAVE_OPENGL
/* Sets an integer parameter and updates the video mode if needed. */
static int SetIntAndUpdateVideo(int *ptr, int value)
{
int old_value = *ptr;
if (old_value != value) {
*ptr = value;
if (!VIDEOMODE_Update()) {
*ptr = old_value;
return FALSE;
}
}
return TRUE;
}
int SDL_VIDEO_SetOpengl(int value)
{
if (!SDL_VIDEO_opengl_available)
return FALSE;
return SetIntAndUpdateVideo(&SDL_VIDEO_opengl, value);
}
int SDL_VIDEO_ToggleOpengl(void)
{
return SDL_VIDEO_SetOpengl(!SDL_VIDEO_opengl);
}
#endif /* HAVE_OPENGL */
int SDL_VIDEO_SetVsync(int value)
{
SDL_VIDEO_vsync = value;
VIDEOMODE_Update();
/* Return false if vsync is requested but not available. */
return !SDL_VIDEO_vsync || SDL_VIDEO_vsync_available;
}
int SDL_VIDEO_ToggleVsync(void)
{
return SDL_VIDEO_SetVsync(!SDL_VIDEO_vsync);
}
+90
View File
@@ -0,0 +1,90 @@
#ifndef SDL_VIDEO_H_
#define SDL_VIDEO_H_
#include <stdio.h>
#include <SDL.h>
#include "config.h"
#include "videomode.h"
/* Native BPP of the desktop. OpenGL modes can be opened only
in the native BPP. */
extern int SDL_VIDEO_native_bpp;
/* Current width/height of the screen/window. */
extern int SDL_VIDEO_width;
extern int SDL_VIDEO_height;
/* Indicates current display mode */
extern VIDEOMODE_MODE_t SDL_VIDEO_current_display_mode;
extern SDL_Surface *SDL_VIDEO_screen;
#if HAVE_OPENGL
/* Indicates whenther OpenGL is available on the host machine. */
extern int SDL_VIDEO_opengl_available;
/* Get/set video hardware acceleration. */
/* Call VIDEOMODE_Update() after changing this variable, or use SDL_VIDEO_SetOpengl() instead. */
extern int SDL_VIDEO_opengl;
int SDL_VIDEO_SetOpengl(int value);
int SDL_VIDEO_ToggleOpengl(void);
#endif /* HAVE_OPENGL */
/* Get/set the vertical synchronisation feature. */
/* Call VIDEOMODE_Update() after changing this variable, or use SDL_VIDEO_SetVsync() instead. */
extern int SDL_VIDEO_vsync;
/* If Vsync is requested but not available in the current video mode, these
functions return FALSE and set SDL_VIDEO_vsync_available to FALSE; else the returned and
set values are TRUE. */
int SDL_VIDEO_SetVsync(int value);
int SDL_VIDEO_ToggleVsync(void);
extern int SDL_VIDEO_vsync_available;
/* Get/set brightness of scanlines. (0=none, 100=completely black). */
/* Use SDL_VIDEO_SetScanlinesPercentage() to set this value. */
extern int SDL_VIDEO_scanlines_percentage;
void SDL_VIDEO_SetScanlinesPercentage(int value);
/* Get/set scanlines interplation, both in sowtfare and in OpenGL mode. */
/* Use SDL_VIDEO_SetInterpolateScanlines() to set this value. */
extern int SDL_VIDEO_interpolate_scanlines;
void SDL_VIDEO_SetInterpolateScanlines(int value);
void SDL_VIDEO_ToggleInterpolateScanlines(void);
/* Initialise the SDL video subsystem. */
void SDL_VIDEO_InitSDL(void);
/* Close the SDL video subsystem. */
void SDL_VIDEO_QuitSDL(void);
/* Close and restart the SDL video subsystem. */
void SDL_VIDEO_ReinitSDL(void);
int SDL_VIDEO_ReadConfig(char *option, char *parameters);
void SDL_VIDEO_WriteConfig(FILE *fp);
int SDL_VIDEO_Initialise(int *argc, char *argv[]);
void SDL_VIDEO_Exit(void);
/* Write the screen data into DEST. */
void SDL_VIDEO_BlitNormal8(Uint32 *dest, Uint8 *src, int pitch, int width, int height);
void SDL_VIDEO_BlitNormal16(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint16 *palette16);
void SDL_VIDEO_BlitNormal32(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint32 *palette32);
void SDL_VIDEO_BlitXEP80_8(Uint32 *dest, Uint8 *src, int pitch, int width, int height);
void SDL_VIDEO_BlitXEP80_16(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint16 *palette16);
void SDL_VIDEO_BlitXEP80_32(Uint32 *dest, Uint8 *src, int pitch, int width, int height, Uint32 *palette32);
void SDL_VIDEO_BlitProto80_8(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line);
void SDL_VIDEO_BlitProto80_16(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, Uint16 *palette16);
void SDL_VIDEO_BlitProto80_32(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, Uint32 *palette32);
#ifdef AF80
void SDL_VIDEO_BlitAF80_8(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink);
void SDL_VIDEO_BlitAF80_16(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint16 *palette16);
void SDL_VIDEO_BlitAF80_32(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint32 *palette32);
#endif
#ifdef BIT3
void SDL_VIDEO_BlitBIT3_8(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink);
void SDL_VIDEO_BlitBIT3_16(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint16 *palette16);
void SDL_VIDEO_BlitBIT3_32(Uint32 *dest, int first_column, int last_column, int pitch, int first_line, int last_line, int blink, Uint32 *palette32);
#endif
/* Update lookup tables for the blit functions. */
void SDL_VIDEO_UpdatePaletteLookup(VIDEOMODE_MODE_t mode, int bpp_32);
#endif /* SDL_VIDEO_H_ */
+981
View File
@@ -0,0 +1,981 @@
/*
* sdl/video_gl.c - SDL library specific port code - OpenGL accelerated video display
*
* Copyright (c) 2010 Tomasz Krasuski
* Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <SDL.h>
#include <SDL_opengl.h>
#include "af80.h"
#include "bit3.h"
#include "artifact.h"
#include "atari.h"
#include "cfg.h"
#include "colours.h"
#include "config.h"
#include "filter_ntsc.h"
#include "log.h"
#include "pbi_proto80.h"
#ifdef PAL_BLENDING
#include "pal_blending.h"
#endif /* PAL_BLENDING */
#include "platform.h"
#include "screen.h"
#include "videomode.h"
#include "xep80.h"
#include "xep80_fonts.h"
#include "util.h"
#include "sdl/palette.h"
#include "sdl/video.h"
#include "sdl/video_gl.h"
static int currently_rotated = FALSE;
/* If TRUE, then 32 bit, else 16 bit screen. */
static int bpp_32 = FALSE;
int SDL_VIDEO_GL_filtering = 0;
int SDL_VIDEO_GL_pixel_format = SDL_VIDEO_GL_PIXEL_FORMAT_BGR16;
/* Path to the OpenGL shared library. */
static char const *library_path = NULL;
/* Pointers to OpenGL functions, loaded dynamically during initialisation. */
static struct
{
void(APIENTRY*Viewport)(GLint,GLint,GLsizei,GLsizei);
void(APIENTRY*ClearColor)(GLfloat, GLfloat, GLfloat, GLfloat);
void(APIENTRY*Clear)(GLbitfield);
void(APIENTRY*Enable)(GLenum);
void(APIENTRY*Disable)(GLenum);
void(APIENTRY*GenTextures)(GLsizei, GLuint*);
void(APIENTRY*DeleteTextures)(GLsizei, const GLuint*);
void(APIENTRY*BindTexture)(GLenum, GLuint);
void(APIENTRY*TexParameteri)(GLenum, GLenum, GLint);
void(APIENTRY*TexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*);
void(APIENTRY*TexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*);
void(APIENTRY*TexCoord2f)(GLfloat, GLfloat);
void(APIENTRY*Vertex3f)(GLfloat, GLfloat, GLfloat);
void(APIENTRY*Color4f)(GLfloat, GLfloat, GLfloat, GLfloat);
void(APIENTRY*BlendFunc)(GLenum,GLenum);
void(APIENTRY*MatrixMode)(GLenum);
void(APIENTRY*Ortho)(GLdouble,GLdouble,GLdouble,GLdouble,GLdouble,GLdouble);
void(APIENTRY*LoadIdentity)(void);
void(APIENTRY*Begin)(GLenum);
void(APIENTRY*End)(void);
void(APIENTRY*GetIntegerv)(GLenum, GLint*);
const GLubyte*(APIENTRY*GetString)(GLenum);
GLuint(APIENTRY*GenLists)(GLsizei);
void(APIENTRY*DeleteLists)(GLuint, GLsizei);
void(APIENTRY*NewList)(GLuint, GLenum);
void(APIENTRY*EndList)(void);
void(APIENTRY*CallList)(GLuint);
void(APIENTRY*GenBuffers)(GLsizei, GLuint*);
void(APIENTRY*DeleteBuffers)(GLsizei, const GLuint*);
void(APIENTRY*BindBuffer)(GLenum, GLuint);
void(APIENTRY*BufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);
void*(APIENTRY*MapBuffer)(GLenum, GLenum);
GLboolean(APIENTRY*UnmapBuffer)(GLenum);
} gl;
static void DisplayNormal(GLvoid *dest);
#if NTSC_FILTER
static void DisplayNTSCEmu(GLvoid *dest);
#endif
#ifdef XEP80_EMULATION
static void DisplayXEP80(GLvoid *dest);
#endif
#ifdef PBI_PROTO80
static void DisplayProto80(GLvoid *dest);
#endif
#ifdef AF80
static void DisplayAF80(GLvoid *dest);
#endif
#ifdef BIT3
static void DisplayBIT3(GLvoid *dest);
#endif
#ifdef PAL_BLENDING
static void DisplayPalBlending(GLvoid *dest);
#endif /* PAL_BLENDING */
static void (* blit_funcs[VIDEOMODE_MODE_SIZE])(GLvoid *) = {
&DisplayNormal
#if NTSC_FILTER
,&DisplayNTSCEmu
#endif
#ifdef XEP80_EMULATION
,&DisplayXEP80
#endif
#ifdef PBI_PROTO80
,&DisplayProto80
#endif
#ifdef AF80
,&DisplayAF80
#endif
#ifdef BIT3
,&DisplayBIT3
#endif
};
/* GL textures - [0] is screen, [1] is scanlines. */
static GLuint textures[2];
int SDL_VIDEO_GL_pbo = TRUE;
/* Indicates whether Pixel Buffer Objects GL extension is available.
Available from OpenGL 2.1, it gives a significant boost in blit speed. */
static int pbo_available;
/* Name of the main screen Pixel Buffer Object. */
static GLuint screen_pbo;
/* Data for the screen texture. not used when PBOs are used. */
static GLvoid *screen_texture = NULL;
/* 16- and 32-bit ARGB textures, both of size 1x2, used for displaying scanlines.
They contain a transparent black pixel above an opaque black pixel. */
static Uint32 const scanline_tex32[2] = { 0x00000000, 0xff000000 }; /* BGRA 8-8-8-8-REV */
/* The 16-bit one is padded to 32 bits, hence it contains 4 values, not 2. */
static Uint16 const scanline_tex16[4] = { 0x0000, 0x0000, 0x8000, 0x0000 }; /* BGRA 5-5-5-1-REV */
/* Variables used with "subpixel shifting". Screen and scanline textures
sometimes are intentionally shifted by a part of a pixel to look better/clearer. */
static GLfloat screen_vshift;
static GLfloat screen_hshift;
static GLfloat scanline_vshift;
static int paint_scanlines;
/* GL Display List for placing the screen and scanline textures on the screen. */
static GLuint screen_dlist;
static char const * const pixel_format_cfg_strings[SDL_VIDEO_GL_PIXEL_FORMAT_SIZE] = {
"BGR16",
"RGB16",
"BGRA32",
"ARGB32"
};
typedef struct pixel_format_t {
GLint internal_format;
GLenum format;
GLenum type;
Uint32 black_pixel;
Uint32 rmask;
Uint32 gmask;
Uint32 bmask;
void(*calc_pal_func)(void *dest, int const *palette, int size);
void(*ntsc_blit_func)(atari_ntsc_t const*, ATARI_NTSC_IN_T const*, long, int, int, void*, long);
} pixel_format_t;
pixel_format_t const pixel_formats[4] = {
{ GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, 0x0000,
0x0000001f, 0x000007e0, 0x0000f800,
&SDL_PALETTE_Calculate16_B5G6R5, &atari_ntsc_blit_bgr16 },
{ GL_RGB5, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0x0000,
0x0000f800, 0x000007e0, 0x0000001f,
&SDL_PALETTE_Calculate16_R5G6B5, &atari_ntsc_blit_rgb16 }, /* NVIDIA 16-bit */
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, 0xff000000,
0x0000ff00, 0x00ff0000, 0xff000000,
&SDL_PALETTE_Calculate32_B8G8R8A8, &atari_ntsc_blit_bgra32 },
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0xff000000,
0x00ff0000, 0x0000ff00, 0x000000ff,
&SDL_PALETTE_Calculate32_A8R8G8B8, &atari_ntsc_blit_argb32 } /* NVIDIA 32-bit */
};
/* Conversion between function pointers and 'void *' is forbidden in
ISO C, but unfortunately unavoidable when using SDL_GL_GetProcAddress.
So the code below is non-portable and gives a warning with gcc -ansi
-Wall -pedantic, but is the only possible solution. */
static void (*GetGlFunc(const char* s))(void)
{
/* suppress warning: ISO C forbids conversion of object pointer to function pointer type [-pedantic] */
#ifdef __GNUC__
__extension__
#endif
void(*f)(void) = (void(*)(void))SDL_GL_GetProcAddress(s);
if (f == NULL)
Log_print("Unable to get function pointer for %s\n",s);
return f;
}
/* Alocates memory for the screen texture, if needed. */
static void AllocTexture(void)
{
if (!SDL_VIDEO_GL_pbo && screen_texture == NULL)
/* The largest width is in NTSC-filtered full overscan mode - 672 pixels.
The largest height is in PAL XEP-80 mode - 300 pixels. Add 1 pixel at each side
to nicely render screen borders. The texture is 1024x512, which is more than
enough - although it's rounded to powers of 2 to be more compatible (earlier
versions of OpenGL supported only textures with width/height of powers of 2). */
screen_texture = Util_malloc(1024*512*(bpp_32 ? sizeof(Uint32) : sizeof(Uint16)));
}
/* Frees memory for the screen texture, if needed. */
static void FreeTexture(void)
{
if (screen_texture != NULL) {
free(screen_texture);
screen_texture = NULL;
}
}
/* Sets up the initial parameters of the OpenGL context. See also CleanGlContext. */
static void InitGlContext(void)
{
GLint filtering = SDL_VIDEO_GL_filtering ? GL_LINEAR : GL_NEAREST;
gl.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.Clear(GL_COLOR_BUFFER_BIT);
gl.Enable(GL_TEXTURE_2D);
gl.GenTextures(2, textures);
/* Screen texture. */
gl.BindTexture(GL_TEXTURE_2D, textures[0]);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
/* Scanlines texture. */
filtering = SDL_VIDEO_interpolate_scanlines ? GL_LINEAR : GL_NEAREST;
gl.BindTexture(GL_TEXTURE_2D, textures[1]);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gl.MatrixMode(GL_PROJECTION);
gl.LoadIdentity();
gl.Ortho(-1.0, 1.0, -1.0, 1.0, 0.0, 10.0);
gl.MatrixMode(GL_MODELVIEW);
gl.LoadIdentity();
screen_dlist = gl.GenLists(1);
if (SDL_VIDEO_GL_pbo)
gl.GenBuffers(1, &screen_pbo);
}
/* Cleans up the structures allocated in InitGlContext. */
static void CleanGlContext(void)
{
if (SDL_VIDEO_GL_pbo)
gl.DeleteBuffers(1, &screen_pbo);
gl.DeleteLists(screen_dlist, 1);
gl.DeleteTextures(2, textures);
}
/* Sets up the initial parameters of all used textures and the PBO. */
static void InitGlTextures(void)
{
/* Texture for the display surface. */
gl.BindTexture(GL_TEXTURE_2D, textures[0]);
gl.TexImage2D(GL_TEXTURE_2D, 0, pixel_formats[SDL_VIDEO_GL_pixel_format].internal_format, 1024, 512, 0,
pixel_formats[SDL_VIDEO_GL_pixel_format].format, pixel_formats[SDL_VIDEO_GL_pixel_format].type,
NULL);
/* Texture for scanlines. */
gl.BindTexture(GL_TEXTURE_2D, textures[1]);
if (bpp_32)
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
scanline_tex32);
else
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0,
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
scanline_tex16);
if (SDL_VIDEO_GL_pbo) {
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, screen_pbo);
gl.BufferData(GL_PIXEL_UNPACK_BUFFER_ARB, 1024*512*(bpp_32 ? sizeof(Uint32) : sizeof(Uint16)), NULL, GL_DYNAMIC_DRAW_ARB);
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
}
}
void SDL_VIDEO_GL_Cleanup(void)
{
if (SDL_VIDEO_screen != NULL && (SDL_VIDEO_screen->flags & SDL_OPENGL) == SDL_OPENGL)
CleanGlContext();
FreeTexture();
}
void SDL_VIDEO_GL_GetPixelFormat(PLATFORM_pixel_format_t *format)
{
format->bpp = bpp_32 ? 32 : 16;
format->rmask = pixel_formats[SDL_VIDEO_GL_pixel_format].rmask;
format->gmask = pixel_formats[SDL_VIDEO_GL_pixel_format].gmask;
format->bmask = pixel_formats[SDL_VIDEO_GL_pixel_format].bmask;
}
void SDL_VIDEO_GL_MapRGB(void *dest, int const *palette, int size)
{
(*pixel_formats[SDL_VIDEO_GL_pixel_format].calc_pal_func)(dest, palette, size);
}
/* Calculate the palette in the 32-bit BGRA format, or 16-bit BGR 5-6-5 format. */
static void UpdatePaletteLookup(VIDEOMODE_MODE_t mode)
{
SDL_VIDEO_UpdatePaletteLookup(mode, bpp_32);
}
void SDL_VIDEO_GL_PaletteUpdate(void)
{
UpdatePaletteLookup(SDL_VIDEO_current_display_mode);
}
/* Set parameters that will shift the screen and scanline textures a bit,
in order to look better/cleaner on screen. */
static void SetSubpixelShifts(void)
{
int dest_width;
int dest_height;
int vmult, hmult;
if (currently_rotated) {
dest_width = VIDEOMODE_dest_height;
dest_height = VIDEOMODE_dest_width;
} else {
dest_width = VIDEOMODE_dest_width;
dest_height = VIDEOMODE_dest_height;
}
vmult = dest_height / VIDEOMODE_src_height;
hmult = dest_width / VIDEOMODE_src_width;
paint_scanlines = vmult >= 2 && SDL_VIDEO_scanlines_percentage != 0;
if (dest_height % VIDEOMODE_src_height == 0 &&
SDL_VIDEO_GL_filtering &&
!(vmult & 1))
screen_vshift = 0.5 / vmult;
else
screen_vshift = 0.0;
if (dest_height % VIDEOMODE_src_height == 0 &&
((SDL_VIDEO_interpolate_scanlines && !(vmult & 1)) ||
(!SDL_VIDEO_interpolate_scanlines && (vmult & 3) == 3)
)
)
scanline_vshift = -0.25 + 0.5 / vmult;
else
scanline_vshift = -0.25;
if (dest_width % VIDEOMODE_src_width == 0 &&
SDL_VIDEO_GL_filtering &&
!(hmult & 1))
screen_hshift = 0.5 / hmult;
else
screen_hshift = 0.0;
}
/* Sets up the GL Display List that creates a textured rectangle of the main
screen and a second, translucent, rectangle with scanlines. */
static void SetGlDisplayList(void)
{
gl.NewList(screen_dlist, GL_COMPILE);
gl.Clear(GL_COLOR_BUFFER_BIT);
gl.BindTexture(GL_TEXTURE_2D, textures[0]);
gl.Begin(GL_QUADS);
if (currently_rotated) {
gl.TexCoord2f(screen_hshift/1024.0f, ((GLfloat)VIDEOMODE_src_height + screen_vshift)/512.0f);
gl.Vertex3f(1.0f, -1.0f, -2.0f);
gl.TexCoord2f(((GLfloat)VIDEOMODE_actual_width + screen_hshift)/1024.0f, ((GLfloat)VIDEOMODE_src_height + screen_vshift)/512.0f);
gl.Vertex3f(1.0f, 1.0f, -2.0f);
gl.TexCoord2f(((GLfloat)VIDEOMODE_actual_width + screen_hshift)/1024.0f, screen_vshift/512.0f);
gl.Vertex3f(-1.0f, 1.0f, -2.0f);
gl.TexCoord2f(screen_hshift/1024.0f, screen_vshift/512.0f);
gl.Vertex3f(-1.0f, -1.0f, -2.0f);
} else {
gl.TexCoord2f(screen_hshift/1024.0f, ((GLfloat)VIDEOMODE_src_height + screen_vshift)/512.0f);
gl.Vertex3f(-1.0f, -1.0f, -2.0f);
gl.TexCoord2f(((GLfloat)VIDEOMODE_actual_width + screen_hshift)/1024.0f, ((GLfloat)VIDEOMODE_src_height + screen_vshift)/512.0f);
gl.Vertex3f(1.0f, -1.0f, -2.0f);
gl.TexCoord2f(((GLfloat)VIDEOMODE_actual_width + screen_hshift)/1024.0f, screen_vshift/512.0f);
gl.Vertex3f(1.0f, 1.0f, -2.0f);
gl.TexCoord2f(screen_hshift/1024.0f, screen_vshift/512.0f);
gl.Vertex3f(-1.0f, 1.0f, -2.0f);
}
gl.End();
if (paint_scanlines) {
gl.Enable(GL_BLEND);
gl.Color4f(1.0f, 1.0f, 1.0f, ((GLfloat)SDL_VIDEO_scanlines_percentage / 100.0f));
gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl.BindTexture(GL_TEXTURE_2D, textures[1]);
gl.Begin(GL_QUADS);
if (currently_rotated) {
gl.TexCoord2f(0.0f, (GLfloat)VIDEOMODE_src_height + scanline_vshift);
gl.Vertex3f(1.0f, -1.0f, -1.0f);
gl.TexCoord2f(1.0f, (GLfloat)VIDEOMODE_src_height + scanline_vshift);
gl.Vertex3f(1.0f, 1.0f, -1.0f);
gl.TexCoord2f(1.0f, scanline_vshift);
gl.Vertex3f(-1.0f, 1.0f, -1.0f);
gl.TexCoord2f(0.0f, scanline_vshift);
gl.Vertex3f(-1.0f, -1.0f, -1.0f);
} else {
gl.TexCoord2f(0.0f, (GLfloat)VIDEOMODE_src_height + scanline_vshift);
gl.Vertex3f(-1.0f, -1.0f, -1.0f);
gl.TexCoord2f(1.0f, (GLfloat)VIDEOMODE_src_height + scanline_vshift);
gl.Vertex3f(1.0f, -1.0f, -1.0f);
gl.TexCoord2f(1.0f, scanline_vshift);
gl.Vertex3f(1.0f, 1.0f, -1.0f);
gl.TexCoord2f(0.0f, scanline_vshift);
gl.Vertex3f(-1.0f, 1.0f, -1.0f);
}
gl.End();
gl.Disable(GL_BLEND);
}
gl.EndList();
}
/* Resets the screen texture/PBO to all-black. */
static void CleanDisplayTexture(void)
{
GLvoid *ptr;
gl.BindTexture(GL_TEXTURE_2D, textures[0]);
if (SDL_VIDEO_GL_pbo) {
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, screen_pbo);
ptr = gl.MapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
}
else
ptr = screen_texture;
if (bpp_32) {
Uint32* tex = (Uint32 *)ptr;
unsigned int i;
for (i = 0; i < 1024*512; i ++)
/* Set alpha channel to full opacity. */
tex[i] = pixel_formats[SDL_VIDEO_GL_pixel_format].black_pixel;
} else
memset(ptr, 0x00, 1024*512*sizeof(Uint16));
if (SDL_VIDEO_GL_pbo) {
gl.UnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
ptr = NULL;
}
if (bpp_32)
gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1024, 512,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
ptr);
else
gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1024, 512,
GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
ptr);
if (SDL_VIDEO_GL_pbo)
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
}
/* Sets pointers to OpenGL functions. Returns TRUE on success, FALSE on failure. */
static int InitGlFunctions(void)
{
if ((gl.Viewport = (void(APIENTRY*)(GLint,GLint,GLsizei,GLsizei))GetGlFunc("glViewport")) == NULL ||
(gl.ClearColor = (void(APIENTRY*)(GLfloat, GLfloat, GLfloat, GLfloat))GetGlFunc("glClearColor")) == NULL ||
(gl.Clear = (void(APIENTRY*)(GLbitfield))GetGlFunc("glClear")) == NULL ||
(gl.Enable = (void(APIENTRY*)(GLenum))GetGlFunc("glEnable")) == NULL ||
(gl.Disable = (void(APIENTRY*)(GLenum))GetGlFunc("glDisable")) == NULL ||
(gl.GenTextures = (void(APIENTRY*)(GLsizei, GLuint*))GetGlFunc("glGenTextures")) == NULL ||
(gl.DeleteTextures = (void(APIENTRY*)(GLsizei, const GLuint*))GetGlFunc("glDeleteTextures")) == NULL ||
(gl.BindTexture = (void(APIENTRY*)(GLenum, GLuint))GetGlFunc("glBindTexture")) == NULL ||
(gl.TexParameteri = (void(APIENTRY*)(GLenum, GLenum, GLint))GetGlFunc("glTexParameteri")) == NULL ||
(gl.TexImage2D = (void(APIENTRY*)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*))GetGlFunc("glTexImage2D")) == NULL ||
(gl.TexSubImage2D = (void(APIENTRY*)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*))GetGlFunc("glTexSubImage2D")) == NULL ||
(gl.TexCoord2f = (void(APIENTRY*)(GLfloat, GLfloat))GetGlFunc("glTexCoord2f")) == NULL ||
(gl.Vertex3f = (void(APIENTRY*)(GLfloat, GLfloat, GLfloat))GetGlFunc("glVertex3f")) == NULL ||
(gl.Color4f = (void(APIENTRY*)(GLfloat, GLfloat, GLfloat, GLfloat))GetGlFunc("glColor4f")) == NULL ||
(gl.BlendFunc = (void(APIENTRY*)(GLenum,GLenum))GetGlFunc("glBlendFunc")) == NULL ||
(gl.MatrixMode = (void(APIENTRY*)(GLenum))GetGlFunc("glMatrixMode")) == NULL ||
(gl.Ortho = (void(APIENTRY*)(GLdouble,GLdouble,GLdouble,GLdouble,GLdouble,GLdouble))GetGlFunc("glOrtho")) == NULL ||
(gl.LoadIdentity = (void(APIENTRY*)(void))GetGlFunc("glLoadIdentity")) == NULL ||
(gl.Begin = (void(APIENTRY*)(GLenum))GetGlFunc("glBegin")) == NULL ||
(gl.End = (void(APIENTRY*)(void))GetGlFunc("glEnd")) == NULL ||
(gl.GetIntegerv = (void(APIENTRY*)(GLenum, GLint*))GetGlFunc("glGetIntegerv")) == NULL ||
(gl.GetString = (const GLubyte*(APIENTRY*)(GLenum))GetGlFunc("glGetString")) == NULL ||
(gl.GenLists = (GLuint(APIENTRY*)(GLsizei))GetGlFunc("glGenLists")) == NULL ||
(gl.DeleteLists = (void(APIENTRY*)(GLuint, GLsizei))GetGlFunc("glDeleteLists")) == NULL ||
(gl.NewList = (void(APIENTRY*)(GLuint, GLenum))GetGlFunc("glNewList")) == NULL ||
(gl.EndList = (void(APIENTRY*)(void))GetGlFunc("glEndList")) == NULL ||
(gl.CallList = (void(APIENTRY*)(GLuint))GetGlFunc("glCallList")) == NULL)
return FALSE;
return TRUE;
}
/* Checks availability of Pixel Buffer Objests extension and sets pointers of PBO-related OpenGL functions.
Returns TRUE on success, FALSE on failure. */
static int InitGlPbo(void)
{
const GLubyte *extensions = gl.GetString(GL_EXTENSIONS);
if (!strstr((char *)extensions, "EXT_pixel_buffer_object")) {
return FALSE;
}
if ((gl.GenBuffers = (void(APIENTRY*)(GLsizei, GLuint*))GetGlFunc("glGenBuffersARB")) == NULL ||
(gl.DeleteBuffers = (void(APIENTRY*)(GLsizei, const GLuint*))GetGlFunc("glDeleteBuffersARB")) == NULL ||
(gl.BindBuffer = (void(APIENTRY*)(GLenum, GLuint))GetGlFunc("glBindBufferARB")) == NULL ||
(gl.BufferData = (void(APIENTRY*)(GLenum, GLsizeiptr, const GLvoid*, GLenum))GetGlFunc("glBufferDataARB")) == NULL ||
(gl.MapBuffer = (void*(APIENTRY*)(GLenum, GLenum))GetGlFunc("glMapBufferARB")) == NULL ||
(gl.UnmapBuffer = (GLboolean(APIENTRY*)(GLenum))GetGlFunc("glUnmapBufferARB")) == NULL)
return FALSE;
return TRUE;
}
static void ModeInfo(void)
{
const char *fullstring = (SDL_VIDEO_screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ? "fullscreen" : "windowed";
Log_print("Video Mode: %dx%dx%d %s, pixel format: %s", SDL_VIDEO_screen->w, SDL_VIDEO_screen->h,
SDL_VIDEO_screen->format->BitsPerPixel, fullstring, pixel_format_cfg_strings[SDL_VIDEO_GL_pixel_format]);
}
/* Return value of TRUE indicates that the video subsystem was reinitialised. */
static int SetVideoMode(int w, int h, int windowed)
{
int reinit = FALSE;
Uint32 flags = SDL_OPENGL | (windowed ? SDL_RESIZABLE : SDL_FULLSCREEN);
/* In OpenGL mode, the SDL screen is always opened with the default
desktop depth - it is the most compatible way. */
SDL_VIDEO_screen = SDL_SetVideoMode(w, h, SDL_VIDEO_native_bpp, flags);
if (SDL_VIDEO_screen == NULL) {
/* Some SDL_SetVideoMode errors can be averted by reinitialising the SDL video subsystem. */
Log_print("Setting video mode: %dx%dx%d failed: %s. Reinitialising video.", w, h, SDL_VIDEO_native_bpp, SDL_GetError());
SDL_VIDEO_ReinitSDL();
reinit = TRUE;
SDL_VIDEO_screen = SDL_SetVideoMode(w, h, SDL_VIDEO_native_bpp, flags);
if (SDL_VIDEO_screen == NULL) {
Log_print("Setting Video Mode: %dx%dx%d failed: %s", w, h, SDL_VIDEO_native_bpp, SDL_GetError());
Log_flushlog();
exit(-1);
}
}
SDL_VIDEO_width = SDL_VIDEO_screen->w;
SDL_VIDEO_height = SDL_VIDEO_screen->h;
SDL_VIDEO_vsync_available = FALSE;
ModeInfo();
return reinit;
}
int SDL_VIDEO_GL_SetVideoMode(VIDEOMODE_resolution_t const *res, int windowed, VIDEOMODE_MODE_t mode, int rotate90)
{
int isnew = SDL_VIDEO_screen == NULL; /* TRUE means the SDL/GL screen was not yet initialised */
int context_updated = FALSE; /* TRUE means the OpenGL context has been recreated */
currently_rotated = rotate90;
/* Call SetVideoMode only when there was change in width, height, or windowed/fullscreen. */
if (isnew || SDL_VIDEO_screen->w != res->width || SDL_VIDEO_screen->h != res->height ||
((SDL_VIDEO_screen->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) == windowed) {
if (!isnew) {
CleanGlContext();
}
#if HAVE_WINDOWS_H
if (isnew && !windowed) {
/* Switching from fullscreen software mode directly to fullscreen OpenGL mode causes
glitches on Windows (eg. when switched to windowed mode, the window would spontaneously
go back to fullscreen each time it loses and regains focus). We avoid the issue by
switching to a windowed non-OpenGL mode inbetween. */
SDL_SetVideoMode(320, 200, SDL_VIDEO_native_bpp, SDL_RESIZABLE);
}
#endif /* HAVE_WINDOWS_H */
if (SetVideoMode(res->width, res->height, windowed))
/* Reinitialisation happened! Need to recreate GL context. */
isnew = TRUE;
if (!InitGlFunctions()) {
Log_print("Cannot use OpenGL - some functions are not provided.");
return FALSE;
}
if (isnew) {
GLint tex_size;
gl.GetIntegerv(GL_MAX_TEXTURE_SIZE, & tex_size);
if (tex_size < 1024) {
Log_print("Cannot use OpenGL - Supported texture size is too small (%d).", tex_size);
return FALSE;
}
}
pbo_available = InitGlPbo();
if (!pbo_available)
SDL_VIDEO_GL_pbo = FALSE;
if (isnew) {
Log_print("OpenGL initialized successfully. Version: %s", gl.GetString(GL_VERSION));
if (pbo_available)
Log_print("OpenGL Pixel Buffer Objects available.");
else
Log_print("OpenGL Pixel Buffer Objects not available.");
}
InitGlContext();
context_updated = TRUE;
}
if (isnew) {
FreeTexture();
AllocTexture();
}
UpdatePaletteLookup(mode);
if (context_updated)
InitGlTextures();
SDL_ShowCursor(SDL_DISABLE); /* hide mouse cursor */
if (mode == VIDEOMODE_MODE_NORMAL) {
#ifdef PAL_BLENDING
if (ARTIFACT_mode == ARTIFACT_PAL_BLEND)
blit_funcs[0] = &DisplayPalBlending;
else
#endif /* PAL_BLENDING */
blit_funcs[0] = &DisplayNormal;
}
gl.Viewport(VIDEOMODE_dest_offset_left, VIDEOMODE_dest_offset_top, VIDEOMODE_dest_width, VIDEOMODE_dest_height);
SetSubpixelShifts();
SetGlDisplayList();
CleanDisplayTexture();
return TRUE;
}
int SDL_VIDEO_GL_SupportsVideomode(VIDEOMODE_MODE_t mode, int stretch, int rotate90)
{
/* OpenGL supports rotation and stretching in all display modes. */
return TRUE;
}
static void DisplayNormal(GLvoid *dest)
{
Uint8 *screen = (Uint8 *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
if (bpp_32)
SDL_VIDEO_BlitNormal32((Uint32*)dest, screen, VIDEOMODE_actual_width, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp32);
else {
int pitch;
if (VIDEOMODE_actual_width & 0x01)
pitch = VIDEOMODE_actual_width / 2 + 1;
else
pitch = VIDEOMODE_actual_width / 2;
SDL_VIDEO_BlitNormal16((Uint32*)dest, screen, pitch, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp16);
}
}
#ifdef PAL_BLENDING
static void DisplayPalBlending(GLvoid *dest)
{
Uint8 *screen = (Uint8 *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
if (bpp_32)
PAL_BLENDING_Blit32((ULONG*)dest, screen, VIDEOMODE_actual_width, VIDEOMODE_src_width, VIDEOMODE_src_height, VIDEOMODE_src_offset_top % 2);
else {
int pitch;
if (VIDEOMODE_actual_width & 0x01)
pitch = VIDEOMODE_actual_width / 2 + 1;
else
pitch = VIDEOMODE_actual_width / 2;
PAL_BLENDING_Blit16((ULONG*)dest, screen, pitch, VIDEOMODE_src_width, VIDEOMODE_src_height, VIDEOMODE_src_offset_top % 2);
}
}
#endif /* PAL_BLENDING */
#if NTSC_FILTER
static void DisplayNTSCEmu(GLvoid *dest)
{
(*pixel_formats[SDL_VIDEO_GL_pixel_format].ntsc_blit_func)(
FILTER_NTSC_emu,
(ATARI_NTSC_IN_T *) ((UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left),
Screen_WIDTH,
VIDEOMODE_src_width,
VIDEOMODE_src_height,
dest,
VIDEOMODE_actual_width * (bpp_32 ? 4 : 2));
}
#endif
#ifdef XEP80_EMULATION
static void DisplayXEP80(GLvoid *dest)
{
static int xep80Frame = 0;
Uint8 *screen;
xep80Frame++;
if (xep80Frame == 60) xep80Frame = 0;
if (xep80Frame > 29)
screen = XEP80_screen_1;
else
screen = XEP80_screen_2;
screen += XEP80_SCRN_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
if (bpp_32)
SDL_VIDEO_BlitXEP80_32((Uint32*)dest, screen, VIDEOMODE_actual_width, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp32);
else
SDL_VIDEO_BlitXEP80_16((Uint32*)dest, screen, VIDEOMODE_actual_width / 2, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp16);
}
#endif
#ifdef PBI_PROTO80
static void DisplayProto80(GLvoid *dest)
{
int first_column = (VIDEOMODE_src_offset_left+7) / 8;
int last_column = (VIDEOMODE_src_offset_left + VIDEOMODE_src_width) / 8;
int first_line = VIDEOMODE_src_offset_top;
int last_line = first_line + VIDEOMODE_src_height;
if (bpp_32)
SDL_VIDEO_BlitProto80_32((Uint32*)dest, first_column, last_column, VIDEOMODE_actual_width, first_line, last_line, SDL_PALETTE_buffer.bpp32);
else
SDL_VIDEO_BlitProto80_16((Uint32*)dest, first_column, last_column, VIDEOMODE_actual_width/2, first_line, last_line, SDL_PALETTE_buffer.bpp16);
}
#endif
#ifdef AF80
static void DisplayAF80(GLvoid *dest)
{
int first_column = (VIDEOMODE_src_offset_left+7) / 8;
int last_column = (VIDEOMODE_src_offset_left + VIDEOMODE_src_width) / 8;
int first_line = VIDEOMODE_src_offset_top;
int last_line = first_line + VIDEOMODE_src_height;
static int AF80Frame = 0;
int blink;
AF80Frame++;
if (AF80Frame == 60) AF80Frame = 0;
blink = AF80Frame >= 30;
if (bpp_32)
SDL_VIDEO_BlitAF80_32((Uint32*)dest, first_column, last_column, VIDEOMODE_actual_width, first_line, last_line, blink, SDL_PALETTE_buffer.bpp32);
else
SDL_VIDEO_BlitAF80_16((Uint32*)dest, first_column, last_column, VIDEOMODE_actual_width/2, first_line, last_line, blink, SDL_PALETTE_buffer.bpp16);
}
#endif
#ifdef BIT3
static void DisplayBIT3(GLvoid *dest)
{
int first_column = (VIDEOMODE_src_offset_left+7) / 8;
int last_column = (VIDEOMODE_src_offset_left + VIDEOMODE_src_width) / 8;
int first_line = VIDEOMODE_src_offset_top;
int last_line = first_line + VIDEOMODE_src_height;
static int BIT3Frame = 0;
int blink;
BIT3Frame++;
if (BIT3Frame == 60) BIT3Frame = 0;
blink = BIT3Frame >= 30;
if (bpp_32)
SDL_VIDEO_BlitBIT3_32((Uint32*)dest, first_column, last_column, VIDEOMODE_actual_width, first_line, last_line, blink, SDL_PALETTE_buffer.bpp32);
else
SDL_VIDEO_BlitBIT3_16((Uint32*)dest, first_column, last_column, VIDEOMODE_actual_width/2, first_line, last_line, blink, SDL_PALETTE_buffer.bpp16);
}
#endif
void SDL_VIDEO_GL_DisplayScreen(void)
{
gl.BindTexture(GL_TEXTURE_2D, textures[0]);
if (SDL_VIDEO_GL_pbo) {
GLvoid *ptr;
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, screen_pbo);
ptr = gl.MapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB);
(*blit_funcs[SDL_VIDEO_current_display_mode])(ptr);
gl.UnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEOMODE_actual_width, VIDEOMODE_src_height,
pixel_formats[SDL_VIDEO_GL_pixel_format].format, pixel_formats[SDL_VIDEO_GL_pixel_format].type,
NULL);
gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
} else {
(*blit_funcs[SDL_VIDEO_current_display_mode])(screen_texture);
gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEOMODE_actual_width, VIDEOMODE_src_height,
pixel_formats[SDL_VIDEO_GL_pixel_format].format, pixel_formats[SDL_VIDEO_GL_pixel_format].type,
screen_texture);
}
gl.CallList(screen_dlist);
SDL_GL_SwapBuffers();
}
int SDL_VIDEO_GL_ReadConfig(char *option, char *parameters)
{
if (strcmp(option, "PIXEL_FORMAT") == 0) {
int i = CFG_MatchTextParameter(parameters, pixel_format_cfg_strings, SDL_VIDEO_GL_PIXEL_FORMAT_SIZE);
if (i < 0)
return FALSE;
SDL_VIDEO_GL_pixel_format = i;
}
else if (strcmp(option, "BILINEAR_FILTERING") == 0)
return (SDL_VIDEO_GL_filtering = Util_sscanbool(parameters)) != -1;
else if (strcmp(option, "OPENGL_PBO") == 0)
return (SDL_VIDEO_GL_pbo = Util_sscanbool(parameters)) != -1;
else
return FALSE;
return TRUE;
}
void SDL_VIDEO_GL_WriteConfig(FILE *fp)
{
fprintf(fp, "PIXEL_FORMAT=%s\n", pixel_format_cfg_strings[SDL_VIDEO_GL_pixel_format]);
fprintf(fp, "BILINEAR_FILTERING=%d\n", SDL_VIDEO_GL_filtering);
fprintf(fp, "OPENGL_PBO=%d\n", SDL_VIDEO_GL_pbo);
}
/* Loads the OpenGL library. Return TRUE on success, FALSE on failure. */
static int InitGlLibrary(void)
{
if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0) {
Log_print("Cannot use OpenGL - unable to set GL attribute: %s\n",SDL_GetError());
return FALSE;
}
if (SDL_GL_LoadLibrary(library_path) < 0) {
Log_print("Cannot use OpenGL - unable to dynamically open OpenGL library: %s\n",SDL_GetError());
return FALSE;
}
return TRUE;
}
void SDL_VIDEO_GL_InitSDL(void)
{
SDL_VIDEO_opengl_available = InitGlLibrary();
}
int SDL_VIDEO_GL_Initialise(int *argc, char *argv[])
{
int i, j;
int help_only = FALSE;
for (i = j = 1; i < *argc; i++) {
int i_a = (i + 1 < *argc); /* is argument available? */
int a_m = FALSE; /* error, argument missing! */
int a_i = FALSE; /* error, argument invalid! */
if (strcmp(argv[i], "-pixel-format") == 0) {
if (i_a) {
if ((SDL_VIDEO_GL_pixel_format = CFG_MatchTextParameter(argv[++i], pixel_format_cfg_strings, SDL_VIDEO_GL_PIXEL_FORMAT_SIZE)) < 0)
a_i = TRUE;
}
else a_m = TRUE;
}
else if (strcmp(argv[i], "-bilinear-filter") == 0)
SDL_VIDEO_GL_filtering = TRUE;
else if (strcmp(argv[i], "-no-bilinear-filter") == 0)
SDL_VIDEO_GL_filtering = FALSE;
else if (strcmp(argv[i], "-pbo") == 0)
SDL_VIDEO_GL_pbo = TRUE;
else if (strcmp(argv[i], "-no-pbo") == 0)
SDL_VIDEO_GL_pbo = FALSE;
else if (strcmp(argv[i], "-opengl-lib") == 0) {
if (i_a)
library_path = argv[++i];
else a_m = TRUE;
}
else {
if (strcmp(argv[i], "-help") == 0) {
help_only = TRUE;
Log_print("\t-pixel-format bgr16|rgb16|bgra32|argb32");
Log_print("\t Set internal pixel format (affects performance)");
Log_print("\t-bilinear-filter Enable OpenGL bilinear filtering");
Log_print("\t-no-bilinear-filter Disable OpenGL bilinear filtering");
Log_print("\t-pbo Use OpenGL Pixel Buffer Objects if available");
Log_print("\t-no-pbo Don't use OpenGL Pixel Buffer Objects");
Log_print("\t-opengl-lib <path> Use a custom OpenGL shared library");
}
argv[j++] = argv[i];
}
if (a_m) {
Log_print("Missing argument for '%s'", argv[i]);
return FALSE;
} else if (a_i) {
Log_print("Invalid argument for '%s'", argv[--i]);
return FALSE;
}
}
*argc = j;
if (help_only)
return TRUE;
bpp_32 = SDL_VIDEO_GL_pixel_format >= SDL_VIDEO_GL_PIXEL_FORMAT_BGRA32;
return TRUE;
}
void SDL_VIDEO_GL_SetPixelFormat(int value)
{
SDL_VIDEO_GL_pixel_format = value;
if (SDL_VIDEO_screen != NULL && (SDL_VIDEO_screen->flags & SDL_OPENGL) == SDL_OPENGL) {
int new_bpp_32 = value >= SDL_VIDEO_GL_PIXEL_FORMAT_BGRA32;
if (new_bpp_32 != bpp_32)
{
FreeTexture();
bpp_32 = new_bpp_32;
AllocTexture();
}
UpdatePaletteLookup(SDL_VIDEO_current_display_mode);
InitGlTextures();
CleanDisplayTexture();
}
else
bpp_32 = value;
}
void SDL_VIDEO_GL_TogglePixelFormat(void)
{
SDL_VIDEO_GL_SetPixelFormat((SDL_VIDEO_GL_pixel_format + 1) % SDL_VIDEO_GL_PIXEL_FORMAT_SIZE);
}
void SDL_VIDEO_GL_SetFiltering(int value)
{
SDL_VIDEO_GL_filtering = value;
if (SDL_VIDEO_screen != NULL && (SDL_VIDEO_screen->flags & SDL_OPENGL) == SDL_OPENGL) {
GLint filtering = value ? GL_LINEAR : GL_NEAREST;
gl.BindTexture(GL_TEXTURE_2D, textures[0]);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
SetSubpixelShifts();
SetGlDisplayList();
}
}
void SDL_VIDEO_GL_ToggleFiltering(void)
{
SDL_VIDEO_GL_SetFiltering(!SDL_VIDEO_GL_filtering);
}
int SDL_VIDEO_GL_SetPbo(int value)
{
if (SDL_VIDEO_screen != NULL && (SDL_VIDEO_screen->flags & SDL_OPENGL) == SDL_OPENGL) {
/* Return false if PBOs are requested but not available. */
if (value && !pbo_available)
return FALSE;
CleanGlContext();
FreeTexture();
SDL_VIDEO_GL_pbo = value;
InitGlContext();
AllocTexture();
InitGlTextures();
SetGlDisplayList();
CleanDisplayTexture();
}
else
SDL_VIDEO_GL_pbo = value;
return TRUE;
}
int SDL_VIDEO_GL_TogglePbo(void)
{
return SDL_VIDEO_GL_SetPbo(!SDL_VIDEO_GL_pbo);
}
void SDL_VIDEO_GL_ScanlinesPercentageChanged(void)
{
if (SDL_VIDEO_screen != NULL && (SDL_VIDEO_screen->flags & SDL_OPENGL) == SDL_OPENGL) {
SetSubpixelShifts();
SetGlDisplayList();
}
}
void SDL_VIDEO_GL_InterpolateScanlinesChanged(void)
{
if (SDL_VIDEO_screen != NULL && (SDL_VIDEO_screen->flags & SDL_OPENGL) == SDL_OPENGL) {
GLint filtering = SDL_VIDEO_interpolate_scanlines ? GL_LINEAR : GL_NEAREST;
gl.BindTexture(GL_TEXTURE_2D, textures[1]);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
SetSubpixelShifts();
SetGlDisplayList();
}
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef SDL_VIDEO_GL_H_
#define SDL_VIDEO_GL_H_
#include <stdio.h>
#include "platform.h"
#include "videomode.h"
/* Get/set texture pixel format. On some video cards, either of these is faster. */
enum {
SDL_VIDEO_GL_PIXEL_FORMAT_BGR16,
SDL_VIDEO_GL_PIXEL_FORMAT_RGB16,
SDL_VIDEO_GL_PIXEL_FORMAT_BGRA32,
SDL_VIDEO_GL_PIXEL_FORMAT_ARGB32,
/* Number of values in enumerator */
SDL_VIDEO_GL_PIXEL_FORMAT_SIZE
};
/* Call SDL_VIDEO_GL_SetPixelFormat() after changing this variable. */
extern int SDL_VIDEO_GL_pixel_format;
void SDL_VIDEO_GL_SetPixelFormat(int value);
void SDL_VIDEO_GL_TogglePixelFormat(void);
/* Returns parameters of the current display pixel format. Used when computing
lookup tables used for blitting the Atari screen to display surface. */
void SDL_VIDEO_GL_GetPixelFormat(PLATFORM_pixel_format_t *format);
/* Convert a table of RGB values, PALETTE, of size SIZE, to a display's native
format and store it in the lookup table DEST. */
void SDL_VIDEO_GL_MapRGB(void *dest, int const *palette, int size);
/* Get/set bilinear filtering. */
/* Call VIDEOMODE_Update() after changing this variable, or use SDL_VIDEO_GL_SetFiltering() instead. */
extern int SDL_VIDEO_GL_filtering;
void SDL_VIDEO_GL_SetFiltering(int value);
void SDL_VIDEO_GL_ToggleFiltering(void);
/* Get/set usage of Pixel Buffer Objects if available. */
/* Call VIDEOMODE_Update() after changing this variable, or use SDL_VIDEO_GL_SetPbo() instead. */
extern int SDL_VIDEO_GL_pbo;
/* If PBOs are requested but not available, these functions return FALSE. Note: Testing for
availibility of PBOs is only possible when OpenGL is active. If the host doesn't support PBOs
but OpenGL mode is not active, the functions will return TRUE. */
int SDL_VIDEO_GL_SetPbo(int value);
int SDL_VIDEO_GL_TogglePbo(void);
void SDL_VIDEO_GL_ScanlinesPercentageChanged(void);
void SDL_VIDEO_GL_InterpolateScanlinesChanged(void);
/* Called when switching back to software mode. Cleans the OpenGL context and frees structures. */
void SDL_VIDEO_GL_Cleanup(void);
void SDL_VIDEO_GL_DisplayScreen(void);
void SDL_VIDEO_GL_PaletteUpdate(void);
int SDL_VIDEO_GL_SetVideoMode(VIDEOMODE_resolution_t const *res, int windowed, VIDEOMODE_MODE_t mode, int rotate90);
int SDL_VIDEO_GL_SupportsVideomode(VIDEOMODE_MODE_t mode, int stretch, int rotate90);
int SDL_VIDEO_GL_ReadConfig(char *option, char *parameters);
void SDL_VIDEO_GL_WriteConfig(FILE *fp);
int SDL_VIDEO_GL_Initialise(int *argc, char *argv[]);
/* Initialise SDL GL subsystem. Must be called after SDL video initialisation
(SDL_VIDEO_InitSDL()). */
void SDL_VIDEO_GL_InitSDL(void);
#endif /* SDL_VIDEO_GL_H_ */
+881
View File
@@ -0,0 +1,881 @@
/*
* sdl/video_sw.c - SDL library specific port code - software-based video display
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 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.
*
* Atari800 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 Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include <SDL.h>
#include "af80.h"
#include "bit3.h"
#include "artifact.h"
#include "atari.h"
#include "colours.h"
#include "config.h"
#include "filter_ntsc.h"
#include "log.h"
#include "pbi_proto80.h"
#ifdef PAL_BLENDING
#include "pal_blending.h"
#endif /* PAL_BLENDING */
#include "platform.h"
#include "screen.h"
#include "videomode.h"
#include "xep80.h"
#include "xep80_fonts.h"
#include "util.h"
#include "sdl/palette.h"
#include "sdl/video.h"
#include "sdl/video_sw.h"
static int fullscreen = 1;
int SDL_VIDEO_SW_bpp = 0;
static void DisplayWithoutScaling(void);
static void DisplayWithScaling(void);
static void DisplayRotated(void);
#ifdef NTSC_FILTER
static void DisplayNTSCEmu(void);
#endif
#ifdef XEP80_EMULATION
static void DisplayXEP80(void);
#endif
#ifdef PBI_PROTO80
static void DisplayProto80(void);
#endif
#ifdef AF80
static void DisplayAF80(void);
#endif
#ifdef BIT3
static void DisplayBIT3(void);
#endif
#ifdef PAL_BLENDING
static void DisplayPalBlending(void);
static void DisplayPalBlendingScaled(void);
#endif /* PAL_BLENDING */
static void (*blit_funcs[VIDEOMODE_MODE_SIZE])(void) = {
&DisplayWithoutScaling
#ifdef NTSC_FILTER
,&DisplayNTSCEmu
#endif
#ifdef XEP80_EMULATION
,&DisplayXEP80
#endif
#ifdef PBI_PROTO80
,&DisplayProto80
#endif
#ifdef AF80
,&DisplayAF80
#endif
#ifdef BIT3
,&DisplayBIT3
#endif
};
static void Set8BitPalette(VIDEOMODE_MODE_t mode)
{
int *pal = SDL_PALETTE_tab[mode].palette;
int size = SDL_PALETTE_tab[mode].size;
SDL_Color colors[256];
int i, rgb;
for (i = 0; i < size; i++) {
rgb = pal[i];
colors[i].r = (rgb & 0x00ff0000) >> 16;
colors[i].g = (rgb & 0x0000ff00) >> 8;
colors[i].b = (rgb & 0x000000ff) >> 0;
}
/* As the data that will be written to SDL_VIDEO_screen is already palettised,
SDL_SetPalette shouldn't modify the surface's logical palette (so no
SDL_LOGPAL here). Adding SDL_LOGPAL would break the palette when running
with DirectX video driver in 8bpp fullscreen videomode on Intel GMA 3100. */
SDL_SetPalette(SDL_VIDEO_screen, SDL_PHYSPAL, colors, 0, 256);
}
void SDL_VIDEO_SW_GetPixelFormat(PLATFORM_pixel_format_t *format)
{
format->bpp = SDL_VIDEO_SW_bpp;
format->rmask = SDL_VIDEO_screen->format->Rmask;
format->gmask = SDL_VIDEO_screen->format->Gmask;
format->bmask = SDL_VIDEO_screen->format->Bmask;
}
void SDL_VIDEO_SW_MapRGB(void *dest, int const *palette, int size)
{
int i;
for (i = 0; i < size; ++i) {
Uint32 c = SDL_MapRGB(SDL_VIDEO_screen->format,
(palette[i] & 0x00ff0000) >> 16,
(palette[i] & 0x0000ff00) >> 8,
(palette[i] & 0x000000ff));
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
case 16:
((UWORD *)dest)[i] = (UWORD) c;
break;
case 32:
((ULONG *)dest)[i] = (ULONG) c;
break;
}
}
}
static void UpdatePaletteLookup(VIDEOMODE_MODE_t mode)
{
if (SDL_VIDEO_screen->format->BitsPerPixel == 8)
Set8BitPalette(mode);
else
SDL_VIDEO_UpdatePaletteLookup(mode, SDL_VIDEO_screen->format->BitsPerPixel == 32);
}
void SDL_VIDEO_SW_PaletteUpdate(void)
{
UpdatePaletteLookup(SDL_VIDEO_current_display_mode);
}
static void ModeInfo(void)
{
const char *fullstring = fullscreen ? "fullscreen" : "windowed";
const char *vsyncstring = (SDL_VIDEO_screen->flags & SDL_DOUBLEBUF) ? "with vsync" : "without vsync";
Log_print("Video Mode: %dx%dx%d %s %s", SDL_VIDEO_screen->w, SDL_VIDEO_screen->h,
SDL_VIDEO_screen->format->BitsPerPixel, fullstring, vsyncstring);
}
static void SetVideoMode(int w, int h, int bpp)
{
Uint32 flags = (fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)
| SDL_HWPALETTE;
if (SDL_VIDEO_vsync)
flags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
SDL_VIDEO_screen = SDL_SetVideoMode(w, h, bpp, flags);
if (SDL_VIDEO_screen == NULL) {
/* Some SDL_SetVideoMode errors can be averted by reinitialising the SDL video subsystem. */
Log_print("Setting video mode: %dx%dx%d failed: %s. Reinitialising video.", w, h, bpp, SDL_GetError());
SDL_VIDEO_ReinitSDL();
SDL_VIDEO_screen = SDL_SetVideoMode(w, h, bpp, flags);
if (SDL_VIDEO_screen == NULL) {
Log_print("Setting Video Mode: %dx%dx%d failed: %s", w, h, bpp, SDL_GetError());
Log_flushlog();
exit(-1);
}
}
SDL_VIDEO_width = SDL_VIDEO_screen->w;
SDL_VIDEO_height = SDL_VIDEO_screen->h;
/* When vsync is off, set its availability to TRUE. Otherwise check if
SDL_DOUBLEBUF is supported by the screen. */
SDL_VIDEO_vsync_available = !SDL_VIDEO_vsync || (SDL_VIDEO_screen->flags & SDL_DOUBLEBUF);
ModeInfo();
}
void SDL_VIDEO_SW_SetVideoMode(VIDEOMODE_resolution_t const *res, int windowed, VIDEOMODE_MODE_t mode, int rotate90)
{
int old_bpp = SDL_VIDEO_screen == NULL ? 0 : SDL_VIDEO_screen->format->BitsPerPixel;
if (SDL_VIDEO_SW_bpp == 0) {
/* Autodetect bpp */
if ((SDL_VIDEO_native_bpp != 8) && (SDL_VIDEO_native_bpp != 16) && (SDL_VIDEO_native_bpp != 32)) {
Log_print("Native BPP of %i not supported, setting 8bit mode (slow conversion)", SDL_VIDEO_native_bpp);
SDL_VIDEO_SW_bpp = 8;
} else
SDL_VIDEO_SW_bpp = SDL_VIDEO_native_bpp;
}
if ((rotate90 && SDL_VIDEO_SW_bpp != 16) ||
((0
#ifdef NTSC_FILTER
|| mode == VIDEOMODE_MODE_NTSC_FILTER
#endif
#ifdef PAL_BLENDING
|| (mode == VIDEOMODE_MODE_NORMAL && ARTIFACT_mode == ARTIFACT_PAL_BLEND)
#endif /* PAL_BLENDING */
) && SDL_VIDEO_SW_bpp != 16 && SDL_VIDEO_SW_bpp != 32)) {
/* Rotate90 supports only 16bpp; NTSC filter and PAL blending don't support 8bpp. */
SDL_VIDEO_SW_bpp = 16;
}
/* Call SetVideoMode only when there was change in width, height, bpp, windowed/fullscreen, or vsync. */
if (SDL_VIDEO_screen == NULL || SDL_VIDEO_screen->w != res->width || SDL_VIDEO_screen->h != res->height || old_bpp != SDL_VIDEO_SW_bpp ||
fullscreen == windowed || (SDL_VIDEO_vsync && SDL_VIDEO_vsync_available) != ((SDL_VIDEO_screen->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF)) {
fullscreen = !windowed;
SetVideoMode(res->width, res->height, SDL_VIDEO_SW_bpp);
}
UpdatePaletteLookup(mode);
/* Clear the screen. */
SDL_FillRect(SDL_VIDEO_screen, NULL, 0);
SDL_Flip(SDL_VIDEO_screen);
if (SDL_VIDEO_vsync_available)
/* Also clear the backbuffer. */
SDL_FillRect(SDL_VIDEO_screen, NULL, 0);
SDL_ShowCursor(SDL_DISABLE); /* hide mouse cursor */
if (mode == VIDEOMODE_MODE_NORMAL) {
if (rotate90)
blit_funcs[0] = &DisplayRotated;
#ifdef PAL_BLENDING
else if (ARTIFACT_mode == ARTIFACT_PAL_BLEND) {
if (VIDEOMODE_src_width == VIDEOMODE_dest_width && VIDEOMODE_src_height == VIDEOMODE_dest_height)
blit_funcs[0] = &DisplayPalBlending;
else
blit_funcs[0] = &DisplayPalBlendingScaled;
}
#endif /* PAL_BLENDING */
else if (VIDEOMODE_src_width == VIDEOMODE_dest_width && VIDEOMODE_src_height == VIDEOMODE_dest_height)
blit_funcs[0] = &DisplayWithoutScaling;
else
blit_funcs[0] = &DisplayWithScaling;
}
}
int SDL_VIDEO_SW_SupportsVideomode(VIDEOMODE_MODE_t mode, int stretch, int rotate90)
{
if (mode == VIDEOMODE_MODE_NORMAL) {
/* Normal mode doesn't support stretching together with rotation. */
return !(stretch && rotate90);
} else
/* Other modes don't support stretching or rotation at all. */
return !stretch && !rotate90;
}
int SDL_VIDEO_SW_SetBpp(int value)
{
int old_value = SDL_VIDEO_SW_bpp;
if (old_value != value) {
SDL_VIDEO_SW_bpp = value;
if (!VIDEOMODE_Update()) {
SDL_VIDEO_SW_bpp = old_value;
return FALSE;
}
}
return TRUE;
}
int SDL_VIDEO_SW_ToggleBpp(void)
{
int new_bpp;
switch (SDL_VIDEO_SW_bpp) {
case 16:
new_bpp = 32;
break;
case 32:
new_bpp = 8;
break;
default: /* 0 or 8 */
new_bpp = 16;
}
return SDL_VIDEO_SW_SetBpp(new_bpp);
}
/* License of scanLines_16():*/
/* This function has been altered from its original version */
/* This license is a verbatim copy of the license of ZLib
* http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses
* This is a free software license, and compatible with the GPL. */
/*****************************************************************************
** Original Source: /cvsroot/bluemsx/blueMSX/Src/VideoRender/VideoRender.c,v
**
** Original Revision: 1.25
**
** Original Date: 2006/01/17 08:49:34
**
** More info: http://www.bluemsx.com
**
** Copyright (C) 2003-2004 Daniel Vik
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
******************************************************************************
*/
/* Modified version, which optionally uses interpolation (slower but better).
Caution! This function assumes that the 16-bit screen format is 565
(rrrrrggg gggbbbbb). */
static void scanLines_16(void* pBuffer, int width, int height, int pitch, int scanLinesPct)
{
Uint32* pBuf = (Uint32*)(pBuffer)+pitch/sizeof(Uint32);
Uint32* sBuf = (Uint32*)(pBuffer);
Uint32* tBuf = (Uint32*)(pBuffer)+pitch*2/sizeof(Uint32);
int w, h;
static int prev_scanLinesPct;
pitch = pitch * 2 / (int)sizeof(Uint32);
height /= 2;
width /= 2;
if (scanLinesPct < 0) scanLinesPct = 0;
if (scanLinesPct > 100) scanLinesPct = 100;
if (scanLinesPct == 100) {
if (prev_scanLinesPct != 100) {
/*clean dirty blank scanlines*/
prev_scanLinesPct = 100;
for (h = 0; h < height; h++) {
memset(pBuf, 0, width * sizeof(Uint32));
pBuf += pitch;
}
}
return;
}
prev_scanLinesPct = scanLinesPct;
if (scanLinesPct == 0) {
/* fill in blank scanlines */
for (h = 0; h < height; h++) {
memcpy(pBuf, sBuf, width * sizeof(Uint32));
sBuf += pitch;
pBuf += pitch;
}
return;
}
if (SDL_VIDEO_interpolate_scanlines) {
scanLinesPct = (100-scanLinesPct) * 32 / 200;
for (h = 0; h < height-1; h++) {
for (w = 0; w < width; w++) {
Uint32 pixel = sBuf[w];
Uint32 pixel2 = tBuf[w];
Uint32 a = ((((pixel & 0x07e0f81f)+(pixel2 & 0x07e0f81f)) * scanLinesPct) & 0xfc1f03e0) >> 5;
Uint32 b = ((((pixel >> 5) & 0x07c0f83f)+((pixel2 >> 5) & 0x07c0f83f)) * scanLinesPct) & 0xf81f07e0;
pBuf[w] = a | b;
}
sBuf += pitch;
tBuf += pitch;
pBuf += pitch;
}
} else {
scanLinesPct = (100-scanLinesPct) * 32 / 100;
for (h = 0; h < height; h++) {
for (w = 0; w < width; w++) {
Uint32 pixel = sBuf[w];
Uint32 a = (((pixel & 0x07e0f81f) * scanLinesPct) & 0xfc1f03e0) >> 5;
Uint32 b = (((pixel >> 5) & 0x07c0f83f) * scanLinesPct) & 0xf81f07e0;
pBuf[w] = a | b;
}
sBuf += pitch;
pBuf += pitch;
}
}
}
/* Modified version of scanLines_16, for 32-bit screen.
Caution! This function assumes that the 32-bit screen format is ARGB
(aaaaaaaa rrrrrrrr gggggggg bbbbbbbb). */
static void scanLines_32(void* pBuffer, int width, int height, int pitch, int scanLinesPct)
{
Uint32* pBuf = (Uint32*)(pBuffer)+pitch/sizeof(Uint32);
Uint32* sBuf = (Uint32*)(pBuffer);
Uint32* tBuf = (Uint32*)(pBuffer)+pitch*2/sizeof(Uint32);
int w, h;
static int prev_scanLinesPct;
pitch = pitch * 2 / (int)sizeof(Uint32);
height /= 2;
if (scanLinesPct < 0) scanLinesPct = 0;
if (scanLinesPct > 100) scanLinesPct = 100;
if (scanLinesPct == 100) {
if (prev_scanLinesPct != 100) {
/*clean dirty blank scanlines*/
prev_scanLinesPct = 100;
for (h = 0; h < height; h++) {
memset(pBuf, 0, width * sizeof(Uint32));
pBuf += pitch;
}
}
return;
}
prev_scanLinesPct = scanLinesPct;
if (scanLinesPct == 0) {
/* fill in blank scanlines */
for (h = 0; h < height; h++) {
memcpy(pBuf, sBuf, width * sizeof(Uint32));
sBuf += pitch;
pBuf += pitch;
}
return;
}
if (SDL_VIDEO_interpolate_scanlines) {
scanLinesPct = (100-scanLinesPct) * 256 / 200;
for (h = 0; h < height-1; h++) {
for (w = 0; w < width; w++) {
Uint32 pixel = sBuf[w];
Uint32 pixel2 = tBuf[w];
Uint32 a = ((((pixel & 0x00ff00ff)+(pixel2 & 0x00ff00ff)) * scanLinesPct) & 0xff00ff00) >> 8;
Uint32 b = ((((pixel & 0x0000ff00)+(pixel2 & 0x0000ff00)) >> 8) * scanLinesPct) & 0x0000ff00;
pBuf[w] = a | b;
}
sBuf += pitch;
tBuf += pitch;
pBuf += pitch;
}
} else {
scanLinesPct = (100-scanLinesPct) * 256 / 100;
for (h = 0; h < height; h++) {
for (w = 0; w < width; w++) {
Uint32 pixel = sBuf[w];
Uint32 a = (((pixel & 0x00ff00ff) * scanLinesPct) & 0xff00ff00) >> 8;
Uint32 b = (((pixel & 0x0000ff00) >> 8) * scanLinesPct) & 0x0000ff00;
pBuf[w] = a | b;
}
sBuf += pitch;
pBuf += pitch;
}
}
}
#ifdef XEP80_EMULATION
static void DisplayXEP80(void)
{
static int xep80Frame = 0;
int pitch4 = SDL_VIDEO_screen->pitch / 2;
UBYTE *screen;
Uint8 *pixels = (Uint8 *) SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch * VIDEOMODE_dest_offset_top;
xep80Frame++;
if (xep80Frame == 60) xep80Frame = 0;
if (xep80Frame > 29) {
screen = XEP80_screen_1;
}
else {
screen = XEP80_screen_2;
}
screen += XEP80_SCRN_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
case 8:
pixels += VIDEOMODE_dest_offset_left;
SDL_VIDEO_BlitXEP80_8((Uint32 *)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height);
break;
case 16:
pixels += VIDEOMODE_dest_offset_left * 2;
SDL_VIDEO_BlitXEP80_16((Uint32 *)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp16);
scanLines_16((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
break;
default:
pixels += VIDEOMODE_dest_offset_left * 4;
SDL_VIDEO_BlitXEP80_32((Uint32 *)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp32);
scanLines_32((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
}
}
#endif
#ifdef NTSC_FILTER
static void DisplayNTSCEmu(void)
{
Uint8 *pixels = (Uint8*)SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch * VIDEOMODE_dest_offset_top;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
case 16:
pixels += VIDEOMODE_dest_offset_left * 2;
/* blit atari image, doubled vertically */
atari_ntsc_blit_rgb16(FILTER_NTSC_emu,
(ATARI_NTSC_IN_T *) ((UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left),
Screen_WIDTH,
VIDEOMODE_src_width,
VIDEOMODE_src_height,
pixels,
SDL_VIDEO_screen->pitch * 2);
scanLines_16((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
break;
case 32:
pixels += VIDEOMODE_dest_offset_left * 4;
atari_ntsc_blit_argb32(FILTER_NTSC_emu,
(ATARI_NTSC_IN_T *) ((UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left),
Screen_WIDTH,
VIDEOMODE_src_width,
VIDEOMODE_src_height,
pixels,
SDL_VIDEO_screen->pitch * 2);
scanLines_32((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
break;
}
}
#endif
#ifdef PBI_PROTO80
static void DisplayProto80(void)
{
int first_column = (VIDEOMODE_src_offset_left+7) / 8;
int last_column = (VIDEOMODE_src_offset_left + VIDEOMODE_src_width) / 8;
int first_line = VIDEOMODE_src_offset_top;
int last_line = first_line + VIDEOMODE_src_height;
int pitch4 = SDL_VIDEO_screen->pitch / 2;
Uint8 *pixels = (Uint8*)SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch * VIDEOMODE_dest_offset_top;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
case 8:
pixels += VIDEOMODE_dest_offset_left;
SDL_VIDEO_BlitProto80_8((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line);
break;
case 16:
pixels += VIDEOMODE_dest_offset_left * 2;
SDL_VIDEO_BlitProto80_16((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, SDL_PALETTE_buffer.bpp16);
scanLines_16((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
break;
default:
pixels += VIDEOMODE_dest_offset_left * 4;
SDL_VIDEO_BlitProto80_32((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, SDL_PALETTE_buffer.bpp32);
scanLines_32((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
}
}
#endif
#ifdef AF80
static void DisplayAF80(void)
{
int first_column = (VIDEOMODE_src_offset_left+7) / 8;
int last_column = (VIDEOMODE_src_offset_left + VIDEOMODE_src_width) / 8;
int first_line = VIDEOMODE_src_offset_top;
int last_line = first_line + VIDEOMODE_src_height;
int pitch4 = SDL_VIDEO_screen->pitch / 2;
Uint8 *pixels = (Uint8*)SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch * VIDEOMODE_dest_offset_top;
static int AF80Frame = 0;
int blink;
AF80Frame++;
if (AF80Frame == 60) AF80Frame = 0;
blink = AF80Frame >= 30;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
case 8:
pixels += VIDEOMODE_dest_offset_left;
SDL_VIDEO_BlitAF80_8((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, blink);
break;
case 16:
pixels += VIDEOMODE_dest_offset_left * 2;
SDL_VIDEO_BlitAF80_16((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, blink, SDL_PALETTE_buffer.bpp16);
scanLines_16((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
break;
default:
pixels += VIDEOMODE_dest_offset_left * 4;
SDL_VIDEO_BlitAF80_32((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, blink, SDL_PALETTE_buffer.bpp32);
scanLines_32((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
}
}
#endif
#ifdef BIT3
static void DisplayBIT3(void)
{
int first_column = (VIDEOMODE_src_offset_left+7) / 8;
int last_column = (VIDEOMODE_src_offset_left + VIDEOMODE_src_width) / 8;
int first_line = VIDEOMODE_src_offset_top;
int last_line = first_line + VIDEOMODE_src_height;
int pitch4 = SDL_VIDEO_screen->pitch / 2;
Uint8 *pixels = (Uint8*)SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch * VIDEOMODE_dest_offset_top;
static int BIT3Frame = 0;
int blink;
BIT3Frame++;
if (BIT3Frame == 60) BIT3Frame = 0;
blink = BIT3Frame >= 30;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
case 8:
pixels += VIDEOMODE_dest_offset_left;
SDL_VIDEO_BlitBIT3_8((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, blink);
break;
case 16:
pixels += VIDEOMODE_dest_offset_left * 2;
SDL_VIDEO_BlitBIT3_16((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, blink, SDL_PALETTE_buffer.bpp16);
scanLines_16((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
break;
default:
pixels += VIDEOMODE_dest_offset_left * 4;
SDL_VIDEO_BlitBIT3_32((Uint32 *)pixels, first_column, last_column, pitch4, first_line, last_line, blink, SDL_PALETTE_buffer.bpp32);
scanLines_32((void *)pixels, VIDEOMODE_dest_width, VIDEOMODE_dest_height, SDL_VIDEO_screen->pitch, SDL_VIDEO_scanlines_percentage);
}
}
#endif
static void DisplayRotated(void)
{
unsigned int x, y;
register Uint32 *start32 = (Uint32 *) SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch / 4 * VIDEOMODE_dest_offset_top + VIDEOMODE_dest_offset_left / 2;
int pitch4 = SDL_VIDEO_screen->pitch / 4 - VIDEOMODE_dest_width / 2;
UBYTE *screen = (UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
for (y = 0; y < VIDEOMODE_dest_height; y++) {
for (x = 0; x < VIDEOMODE_dest_width / 2; x++) {
Uint8 left = screen[Screen_WIDTH * (x * 2) + VIDEOMODE_src_width - y];
Uint8 right = screen[Screen_WIDTH * (x * 2 + 1) + VIDEOMODE_src_width - y];
#ifdef WORDS_BIGENDIAN
*start32++ = (SDL_PALETTE_buffer.bpp16[left] << 16) + SDL_PALETTE_buffer.bpp16[right];
#else
*start32++ = (SDL_PALETTE_buffer.bpp16[right] << 16) + SDL_PALETTE_buffer.bpp16[left];
#endif
}
start32 += pitch4;
}
}
static void DisplayWithoutScaling(void)
{
int pitch4 = SDL_VIDEO_screen->pitch / 4;
UBYTE *screen = (UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
Uint8 *pixels = (Uint8 *) SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch * VIDEOMODE_dest_offset_top;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
/* Possible values are 8, 16 and 32, as checked earlier in the
* PLATFORM_SetVideoMode() function. */
case 8:
pixels += VIDEOMODE_dest_offset_left;
SDL_VIDEO_BlitNormal8((Uint32 *)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height);
break;
case 16:
pixels += VIDEOMODE_dest_offset_left * 2;
SDL_VIDEO_BlitNormal16((Uint32*)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp16);
break;
default: /* SDL_VIDEO_screen->format->BitsPerPixel == 32 */
pixels += VIDEOMODE_dest_offset_left * 4;
SDL_VIDEO_BlitNormal32((Uint32 *)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, SDL_PALETTE_buffer.bpp32);
}
}
static void DisplayWithScaling(void)
{
register Uint32 quad;
register int x;
register Uint8 *screen = (UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
register Uint32 *pixels = (Uint32 *) SDL_VIDEO_screen->pixels;
int i;
int y = 0;
int w1;
int w = (VIDEOMODE_src_width) << 16;
int h = (VIDEOMODE_src_height) << 16;
register int dx = w / VIDEOMODE_dest_width;
register int yy;
int pos;
int pitch4 = SDL_VIDEO_screen->pitch / 4;
int dy = h / VIDEOMODE_dest_height;
int init_x = (VIDEOMODE_src_width << 16) - 0x4000;
Uint8 c;
i = VIDEOMODE_dest_height;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
/* Possible values are 8, 16 and 32, as checked earlier in the
* PLATFORM_SetVideoMode() function. */
case 8:
pixels += pitch4 * VIDEOMODE_dest_offset_top + VIDEOMODE_dest_offset_left / 4;
w1 = VIDEOMODE_dest_width / 4 - 1;
while (i > 0) {
x = init_x;
pos = w1;
yy = Screen_WIDTH * (y >> 16);
while (pos >= 0) {
quad = (screen[yy + (x >> 16)] << 24);
x -= dx;
quad += (screen[yy + (x >> 16)] << 16);
x -= dx;
quad += (screen[yy + (x >> 16)] << 8);
x -= dx;
quad += (screen[yy + (x >> 16)] << 0);
x -= dx;
pixels[pos] = quad;
pos--;
}
pixels += pitch4;
y += dy;
i--;
}
break;
case 16:
pixels += pitch4 * VIDEOMODE_dest_offset_top + VIDEOMODE_dest_offset_left / 2;
w1 = VIDEOMODE_dest_width / 2 - 1;
while (i > 0) {
x = init_x;
pos = w1;
yy = Screen_WIDTH * (y >> 16);
while (pos >= 0) {
c = screen[yy + (x >> 16)];
quad = SDL_PALETTE_buffer.bpp16[c] << 16;
x -= dx;
c = screen[yy + (x >> 16)];
quad += SDL_PALETTE_buffer.bpp16[c];
x -= dx;
pixels[pos] = quad;
pos--;
}
pixels += pitch4;
y += dy;
i--;
}
break;
default:
pixels += pitch4 * VIDEOMODE_dest_offset_top + VIDEOMODE_dest_offset_left;
w1 = VIDEOMODE_dest_width - 1;
/* SDL_VIDEO_screen->format->BitsPerPixel = 32 */
while (i > 0) {
x = init_x;
pos = w1;
yy = Screen_WIDTH * (y >> 16);
while (pos >= 0) {
c = screen[yy + (x >> 16)];
quad = SDL_PALETTE_buffer.bpp32[c];
x -= dx;
pixels[pos] = quad;
pos--;
}
pixels += pitch4;
y += dy;
i--;
}
}
}
#ifdef PAL_BLENDING
static void DisplayPalBlending(void)
{
int pitch4 = SDL_VIDEO_screen->pitch / 4;
UBYTE *screen = (UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
Uint8 *pixels = (Uint8 *) SDL_VIDEO_screen->pixels + SDL_VIDEO_screen->pitch * VIDEOMODE_dest_offset_top;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
/* Possible values are 8, 16 and 32, as checked earlier in the
* PLATFORM_SetVideoMode() function. */
case 16:
pixels += VIDEOMODE_dest_offset_left * 2;
PAL_BLENDING_Blit16((ULONG*)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, VIDEOMODE_src_offset_top % 2);
break;
default: /* SDL_VIDEO_screen->format->BitsPerPixel == 32 */
pixels += VIDEOMODE_dest_offset_left * 4;
PAL_BLENDING_Blit32((ULONG *)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, VIDEOMODE_src_offset_top % 2);
}
}
static void DisplayPalBlendingScaled(void)
{
int pitch4 = SDL_VIDEO_screen->pitch / 4;
Uint8 *screen = (UBYTE *)Screen_atari + Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
Uint32 *pixels = (Uint32 *) SDL_VIDEO_screen->pixels;
switch (SDL_VIDEO_screen->format->BitsPerPixel) {
/* Possible values are 8, 16 and 32, as checked earlier in the
* PLATFORM_SetVideoMode() function. */
case 16:
pixels += pitch4 * VIDEOMODE_dest_offset_top + VIDEOMODE_dest_offset_left / 2;
PAL_BLENDING_BlitScaled16((ULONG*)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, VIDEOMODE_dest_width, VIDEOMODE_dest_height, VIDEOMODE_src_offset_top % 2);
break;
case 32:
pixels += pitch4 * VIDEOMODE_dest_offset_top + VIDEOMODE_dest_offset_left;
PAL_BLENDING_BlitScaled32((ULONG*)pixels, screen, pitch4, VIDEOMODE_src_width, VIDEOMODE_src_height, VIDEOMODE_dest_width, VIDEOMODE_dest_height, VIDEOMODE_src_offset_top % 2);
}
}
#endif /* PAL_BLENDING */
void SDL_VIDEO_SW_DisplayScreen(void)
{
if (SDL_LockSurface(SDL_VIDEO_screen) != 0)
/* When the window manager decides to switch the SDL display from
fullscreen to windowed mode (eg. by minimising the window after the
user pressed Alt+Tab in Windows), hardware surface gets disabled
immediately. In such case surface locking will fail. When it happens,
don't blit to screen as it would cause a segfault. When fullscreen
mode gets re-enabled, surface locking will work again and screen
displaying will be restored */
return;
/* Use function corresponding to the current_display_mode. */
(*blit_funcs[SDL_VIDEO_current_display_mode])();
SDL_UnlockSurface(SDL_VIDEO_screen);
/* SDL_UpdateRect is faster than SDL_Flip for a software surface, because
it copies only the used part of the screen. */
if (SDL_VIDEO_screen->flags & SDL_DOUBLEBUF)
SDL_Flip(SDL_VIDEO_screen);
else
SDL_UpdateRect(SDL_VIDEO_screen, VIDEOMODE_dest_offset_left, VIDEOMODE_dest_offset_top, VIDEOMODE_dest_width, VIDEOMODE_dest_height);
}
int SDL_VIDEO_SW_ReadConfig(char *option, char *parameters)
{
if (strcmp(option, "VIDEO_BPP") == 0) {
int value = Util_sscandec(parameters);
if (value != 0 && value != 8 && value != 16 && value != 32)
return FALSE;
else
SDL_VIDEO_SW_bpp = value;
}
else
return FALSE;
return TRUE;
}
void SDL_VIDEO_SW_WriteConfig(FILE *fp)
{
fprintf(fp, "VIDEO_BPP=%d\n", SDL_VIDEO_SW_bpp);
}
int SDL_VIDEO_SW_Initialise(int *argc, char *argv[])
{
int i, j;
for (i = j = 1; i < *argc; i++) {
int i_a = (i + 1 < *argc); /* is argument available? */
int a_m = FALSE; /* error, argument missing! */
if (strcmp(argv[i], "-bpp") == 0) {
if (i_a) {
SDL_VIDEO_SW_bpp = Util_sscandec(argv[++i]);
if (SDL_VIDEO_SW_bpp != 0 && SDL_VIDEO_SW_bpp != 8 && SDL_VIDEO_SW_bpp != 16 && SDL_VIDEO_SW_bpp != 32) {
Log_print("Invalid BPP value %s", argv[i]);
return FALSE;
}
}
else a_m = TRUE;
}
else {
if (strcmp(argv[i], "-help") == 0)
Log_print("\t-bpp <num> Host color depth (0 = autodetect)");
argv[j++] = argv[i];
}
if (a_m) {
Log_print("Missing argument for '%s'", argv[i]);
return FALSE;
}
}
*argc = j;
return TRUE;
}
+32
View File
@@ -0,0 +1,32 @@
#ifndef SDL_VIDEO_SW_H_
#define SDL_VIDEO_SW_H_
#include "platform.h"
#include "videomode.h"
void SDL_VIDEO_SW_DisplayScreen(void);
void SDL_VIDEO_SW_PaletteUpdate(void);
void SDL_VIDEO_SW_SetVideoMode(VIDEOMODE_resolution_t const *res, int windowed, VIDEOMODE_MODE_t mode, int rotate90);
int SDL_VIDEO_SW_SupportsVideomode(VIDEOMODE_MODE_t mode, int stretch, int rotate90);
/* Get/set videomode bits per pixel. */
/* Call VIDEOMODE_Update() after changing this variable, or use SDL_VIDEO_SW_SetBpp() instead. */
extern int SDL_VIDEO_SW_bpp;
int SDL_VIDEO_SW_SetBpp(int value);
int SDL_VIDEO_SW_ToggleBpp(void);
/* Returns parameters of the current display pixel format. Used when computing
lookup tables used for blitting the Atari screen to display surface. */
void SDL_VIDEO_SW_GetPixelFormat(PLATFORM_pixel_format_t *format);
/* Convert a table of RGB values, PALETTE, of size SIZE, to a display's native
format and store it in the lookup table DEST. */
void SDL_VIDEO_SW_MapRGB(void *dest, int const *palette, int size);
/* Read/write to configuration file. */
int SDL_VIDEO_SW_ReadConfig(char *option, char *parameters);
void SDL_VIDEO_SW_WriteConfig(FILE *fp);
/* Initialisation and processing of command-line arguments. */
int SDL_VIDEO_SW_Initialise(int *argc, char *argv[]);
#endif /* SDL_VIDEO_SW_H_ */