Source to src/od-win32/win32gfx.c
/*
* UAE - The Un*x Amiga Emulator
*
* Win32 Drawing and DirectX interface
*
* Copyright 1997-1998 Mathias Ortmann
* Copyright 1997-2000 Brian King
*/
#include "sysconfig.h"
#include <stdlib.h>
#include <stdarg.h>
#include <signal.h>
#include <io.h>
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "uae.h"
#include "memory.h"
#include "custom.h"
#include "events.h"
#include "xwin.h"
#include "keyboard.h"
#include "drawing.h"
#include "picasso96.h"
#include "osdep/win32.h"
#include "osdep/win32gui.h"
#include "osdep/win32gfx.h"
#include "sounddep/sound.h"
/* Local globals */
static uae_u32 current_width, current_height, current_depth;
static int fullscreen = 0; /* fullscreen mode */
static int window_width = 900, window_height = 720, window_depth; /* target resolution */
static int usedirect = 0; /* direct to dx surface (fullscreen or overlay) */
static int overlay = 1; /* use overlay surface */
static int needs_direct; /* is overlay or fullscreen mode required */
static int display_change_requested = 0;
static int mapping_is_mainscreen = 0;
static BOOL bInitDone = FALSE; //?????JGI
int screen_is_picasso = 0;
static BOOL bJustClosedWithActiveMouse = FALSE;
int WIN32GFX_IsPicassoScreen( void )
{
return screen_is_picasso;
}
void WIN32GFX_DisablePicasso( void )
{
picasso_requested_on = 0;
picasso_on = 0;
}
void WIN32GFX_EnablePicasso( void )
{
picasso_requested_on = 1;
}
void WIN32GFX_DisplayChangeRequested( void )
{
display_change_requested = 1;
}
int WIN32GFX_IsFullScreen( void )
{
return fullscreen;
}
int WIN32GFX_GetWidth( void )
{
return current_width;
}
int WIN32GFX_GetHeight( void )
{
return current_height;
}
#ifdef _WIN32_WCE
int nr_joysticks = 1;
void init_joystick( void )
{
}
void read_joystick (int nr, unsigned int *dir, int *button)
{
*dir = *button = 0;
if( nr < nr_joysticks )
{
}
}
void close_joystick( void )
{
}
int check_prefs_changed_gfx (void)
{
return 0;
}
int graphics_init( void )
{
return 1;
}
int graphics_setup( void )
{
return 1;
}
void graphics_leave( void )
{
}
void unlockscr( void )
{
}
int lockscr( void )
{
return 0;
}
void flush_screen( int a, int b )
{
}
void flush_block( int a, int b )
{
}
void flush_line( int a )
{
}
void WIN32GFX_PaletteChange( void )
{
}
#else
#include "osdep/dxwrap.h"
#ifdef __GNUC__
int __cdecl _fcloseall( void );
#endif
/* Local Globals */
static UINT current_pixbytes;
static LPPALETTEENTRY current_palette = NULL;
static BOOL doInit (void);
static void close_windows (void);
uae_u32 default_freq = 0;
HWND hStatusWnd = NULL;
HINSTANCE hDDraw = NULL;
/* For the DX_Invalidate() and gfx_unlock_picasso() functions */
static int p96_double_buffer_first, p96_double_buffer_last, p96_double_buffer_needs_flushing = 0;
static char scrlinebuf[4096]; /* this is too large, but let's rather play on the safe side here */
static int rgbformat_bits (RGBFTYPE t)
{
unsigned long f = 1 << t;
return ((f & RGBMASK_8BIT) != 0 ? 8
: (f & RGBMASK_15BIT) != 0 ? 15
: (f & RGBMASK_16BIT) != 0 ? 16
: (f & RGBMASK_24BIT) != 0 ? 24
: (f & RGBMASK_32BIT) != 0 ? 32
: 0);
}
static int set_ddraw (int width, int height, int wantfull, int wantoverlay, int bits, LPPALETTEENTRY pal)
{
HRESULT ddrval;
bits = (bits + 7) & ~7;
ddrval = DirectDraw_SetCooperativeLevel( hAmigaWnd, wantfull );
if (ddrval != DD_OK)
goto oops;
if (wantfull)
{
write_log ( "set_ddraw: Trying %dx%d, %d bits\n", width, height, bits );
ddrval = DirectDraw_SetDisplayMode( width, height, bits, 0 );
if (ddrval != DD_OK)
{
write_log ( "set_ddraw: Couldn't SetDisplayMode()\n" );
goto oops;
}
ddrval = DirectDraw_GetDisplayMode();
if (ddrval != DD_OK)
{
write_log ( "set_ddraw: Couldn't GetDisplayMode()\n" );
goto oops;
}
}
ddrval = DirectDraw_CreateClipper();
if (ddrval != DD_OK)
{
write_log ( "set_ddraw: No clipping support\n" );
goto oops;
}
ddrval = DirectDraw_CreateSurface( width, height );
if( ddrval != DD_OK )
{
write_log ( "set_ddraw: Couldn't CreateSurface() for primary because %s.\n", DirectDraw_ErrorString( ddrval ) );
goto oops;
}
if( wantoverlay )
{
if( !currprefs.win32_no_overlay && ( DirectDraw_GetPrimaryBitCount() != bits ) )
{
ddrval = DirectDraw_CreateOverlaySurface( width, height, bits );
if( ddrval != DD_OK )
{
write_log ( "set_ddraw: Couldn't CreateOverlaySurface(%d,%d,%d) because %s.\n", width, height, bits, DirectDraw_ErrorString( ddrval ) );
overlay = 0;
}
}
else
{
overlay = 0;
}
}
DirectDraw_ClearSurfaces();
if( !DirectDraw_DetermineLocking( wantfull ) )
{
write_log ( "set_ddraw: Couldn't determine locking.\n" );
goto oops;
}
ddrval = DirectDraw_SetClipper( hAmigaWnd );
if (ddrval != DD_OK)
{
write_log ( "set_ddraw: Couldn't SetHWnd()\n" );
goto oops;
}
current_pixbytes = DirectDraw_GetBytesPerPixel();
write_log ( "set_ddraw() called, and is %dx%d@%d-bytes\n", width, height, current_pixbytes );
if (current_pixbytes == 1) {
current_palette = pal;
ddrval = DirectDraw_CreatePalette( pal );
if (ddrval != DD_OK)
{
write_log ( "set_ddraw: Couldn't CreatePalette()\n" );
goto oops;
}
}
return 1;
oops:
if( wantfull )
DirectDraw_SetCooperativeLevel( hAmigaWnd, 0 ); /* No full-screen, so that people can see our gui_message() */
gui_message("set_ddraw(): DirectDraw initialization failed with %s/%d\n", DirectDraw_ErrorString( ddrval ), ddrval);
return 0;
}
struct win32_displaymode *win32_displaymode_list;
HRESULT CALLBACK modesCallback( LPDDSURFACEDESC2 modeDesc, LPVOID context )
{
struct win32_displaymode **dmpp;
RGBFTYPE colortype;
colortype = DirectDraw_GetSurfacePixelFormat( modeDesc );
if (colortype == RGBFB_NONE || colortype == RGBFB_R8G8B8 || colortype == RGBFB_B8G8R8 )
return DDENUMRET_OK;
dmpp = &win32_displaymode_list;
while (*dmpp != 0) {
if ((*dmpp)->width == modeDesc->dwWidth
&& (*dmpp)->height == modeDesc->dwHeight
&& (*dmpp)->refreshrate == modeDesc->dwRefreshRate)
break;
dmpp = &(*dmpp)->next;
}
if (*dmpp == 0) {
*dmpp = (struct win32_displaymode *)xmalloc (sizeof **dmpp);
(*dmpp)->next = 0;
(*dmpp)->width = modeDesc->dwWidth;
(*dmpp)->height = modeDesc->dwHeight;
(*dmpp)->refreshrate = modeDesc->dwRefreshRate;
(*dmpp)->colormodes = 0;
}
(*dmpp)->colormodes |= 1 << colortype;
return DDENUMRET_OK;
}
static void cleanup_modes( void )
{
struct win32_displaymode *temp = NULL, *dmpp = win32_displaymode_list;
while( dmpp )
{
temp = dmpp;
dmpp = dmpp->next;
free( temp );
}
}
static int our_possible_depths[] = { 8, 15, 16, 24, 32 };
RGBFTYPE WIN32GFX_FigurePixelFormats( RGBFTYPE colortype )
{
HRESULT ddrval;
struct win32_displaymode *dm;
int got_16bit_mode = 0;
int window_created = 0;
if( colortype == 0 ) /* Need to query a 16-bit display mode for its pixel-format. Do this by opening such a screen */
{
hAmigaWnd = CreateWindowEx (WS_EX_TOPMOST,
"AmigaPowah", VersionStr,
WS_VISIBLE | WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT,
1,//GetSystemMetrics (SM_CXSCREEN),
1,//GetSystemMetrics (SM_CYSCREEN),
0, NULL, 0, NULL);
if( hAmigaWnd )
{
window_created = 1;
ddrval = DirectDraw_SetCooperativeLevel( hAmigaWnd, TRUE ); /* TRUE indicates full-screen */
if( ddrval != DD_OK )
{
write_log ( "WIN32GFX_FigurePixelFormats: ERROR - %s\n", DirectDraw_ErrorString(ddrval) );
gui_message( "WIN32GFX_FigurePixelFormats: ERROR - %s\n", DirectDraw_ErrorString(ddrval) );
goto out;
}
}
else
{
write_log ( "WIN32GFX_FigurePixelFormats: ERROR - test-window could not be created.\n" );
gui_message( "WIN32GFX_FigurePixelFormats: ERROR - test-window could not be created.\n" );
}
}
else
{
got_16bit_mode = 1;
}
for (dm = win32_displaymode_list; dm != 0; dm = dm->next)
{
if (!got_16bit_mode)
{
write_log ("figure_pixel_formats: Attempting %dx%d: ", dm->width, dm->height);
ddrval = DirectDraw_SetDisplayMode( dm->width, dm->height, 16, 0 ); /* 0 for default freq */
if (ddrval != DD_OK)
continue;
ddrval = DirectDraw_GetDisplayMode();
if (ddrval != DD_OK)
continue;
colortype = DirectDraw_GetPixelFormat();
if (colortype != RGBFB_NONE)
{
write_log ("%d ", our_possible_depths[2]);
/* Clear the 16-bit information, and get the real stuff! */
dm->colormodes &= ~(RGBFF_R5G6B5PC|RGBFF_R5G5B5PC|RGBFF_R5G6B5|RGBFF_R5G5B5|RGBFF_B5G6R5PC|RGBFF_B5G5R5PC);
dm->colormodes |= 1 << colortype;
got_16bit_mode = 1;
write_log ( "Got real 16-bit colour-depth information: 0x%x\n", colortype );
}
}
else if (dm->colormodes & (RGBFF_R5G6B5PC|RGBFF_R5G5B5PC|RGBFF_R5G6B5|RGBFF_R5G5B5|RGBFF_B5G6R5PC|RGBFF_B5G5R5PC) )
{
/* Clear the 16-bit information, and set the real stuff! */
dm->colormodes &= ~(RGBFF_R5G6B5PC|RGBFF_R5G5B5PC|RGBFF_R5G6B5|RGBFF_R5G5B5|RGBFF_B5G6R5PC|RGBFF_B5G5R5PC);
dm->colormodes |= 1 << colortype;
}
}
out:
if( window_created )
{
Sleep( 2000 );
DestroyWindow( hAmigaWnd );
hAmigaWnd = NULL;
}
return colortype;
}
/* DirectX will fail with "Mode not supported" if we try to switch to a full
* screen mode that doesn't match one of the dimensions we got during enumeration.
* So try to find a best match for the given resolution in our list. */
int WIN32GFX_AdjustScreenmode( uae_u32 *pwidth, uae_u32 *pheight, uae_u32 *ppixbits )
{
struct win32_displaymode *best;
uae_u32 selected_mask = (*ppixbits == 8 ? RGBMASK_8BIT
: *ppixbits == 15 ? RGBMASK_15BIT
: *ppixbits == 16 ? RGBMASK_16BIT
: *ppixbits == 24 ? RGBMASK_24BIT
: RGBMASK_32BIT);
int pass, i = 0, index = 0;
for (pass = 0; pass < 2; pass++)
{
struct win32_displaymode *dm;
uae_u32 mask = (pass == 0
? selected_mask
: RGBMASK_8BIT | RGBMASK_15BIT | RGBMASK_16BIT | RGBMASK_24BIT | RGBMASK_32BIT); /* %%% - BERND, were you missing 15-bit here??? */
i = 0;
index = 0;
best = win32_displaymode_list;
dm = best->next;
while (dm != 0)
{
if ((dm->colormodes & mask) != 0)
{
if (dm->width <= best->width && dm->height <= best->height
&& dm->width >= *pwidth && dm->height >= *pheight)
{
best = dm;
index = i;
}
if (dm->width >= best->width && dm->height >= best->height
&& dm->width <= *pwidth && dm->height <= *pheight)
{
best = dm;
index = i;
}
}
dm = dm->next;
i++;
}
if (best->width == *pwidth && best->height == *pheight)
{
selected_mask = mask; /* %%% - BERND, I added this - does it make sense? Otherwise, I'd specify a 16-bit display-mode for my
Workbench (using -H 2, but SHOULD have been -H 1), and end up with an 8-bit mode instead*/
break;
}
}
*pwidth = best->width;
*pheight = best->height;
if( best->colormodes & selected_mask )
return index;
/* Ordering here is done such that 16-bit is preferred, followed by 15-bit, 8-bit, 32-bit and 24-bit */
if (best->colormodes & RGBMASK_16BIT)
*ppixbits = 16;
else if (best->colormodes & RGBMASK_15BIT) /* %%% - BERND, this possibility was missing? */
*ppixbits = 15;
else if (best->colormodes & RGBMASK_8BIT)
*ppixbits = 8;
else if (best->colormodes & RGBMASK_32BIT)
*ppixbits = 32;
else if (best->colormodes & RGBMASK_24BIT)
*ppixbits = 24;
else
index = -1;
return index;
}
void flush_line( int lineno )
{
}
void flush_block (int a, int b)
{
}
void flush_screen (int a, int b)
{
if( DirectDraw_GetLockableType() == secondary_surface )
{
if( fullscreen )
{
if( DX_Flip() == 0 )
{
DX_Blit( 0, a, 0, a, current_width, b - a + 1, BLIT_SRC );
}
}
else
{
DX_Blit( 0, a, 0, a, current_width, b - a + 1, BLIT_SRC );
}
}
}
static uae_u8 *dolock (void)
{
char *surface = NULL, *oldsurface;
if( !DirectDraw_SurfaceLock( lockable_surface ) )
return 0;
surface = DirectDraw_GetSurfacePointer();
oldsurface = gfxvidinfo.bufmem;
gfxvidinfo.bufmem = surface;
if (surface != oldsurface && ! screen_is_picasso)
{
write_log ("Need to init_row_map\n");
init_row_map ();
}
clear_inhibit_frame (IHF_WINDOWHIDDEN);
return surface;
}
int lockscr( void )
{
return dolock() != 0;
}
uae_u8 *gfx_lock_picasso (void)
{
return dolock ();
}
void gfx_unlock_picasso (void)
{
DirectDraw_SurfaceUnlock();
if( p96_double_buffer_needs_flushing )
{
/* Here, our flush_block() will deal with a offscreen-plain (back-buffer) to visible-surface (front-buffer) */
if( DirectDraw_GetLockableType() == secondary_surface )
{
BOOL relock = FALSE;
if( DirectDraw_IsLocked() )
{
relock = TRUE;
unlockscr();
}
DX_Blit( 0, p96_double_buffer_first,
0, p96_double_buffer_first,
current_width, p96_double_buffer_last - p96_double_buffer_first + 1,
BLIT_SRC );
if( relock )
{
lockscr();
}
}
p96_double_buffer_needs_flushing = 0;
}
}
static void close_hwnds( void )
{
if (hStatusWnd)
{
ShowWindow( hStatusWnd, SW_HIDE );
DestroyWindow (hStatusWnd);
}
if (hAmigaWnd)
{
ShowWindow( hAmigaWnd, SW_HIDE );
DestroyWindow (hAmigaWnd);
}
if (hMainWnd)
{
ShowWindow( hMainWnd, SW_HIDE );
DestroyWindow (hMainWnd);
}
hMainWnd = 0;
hStatusWnd = 0;
hAmigaWnd = 0;
}
static int open_windows (void)
{
static BOOL bFirstTime = TRUE;
char tmpstr[300];
char *fs_warning = 0;
RGBFTYPE colortype;
current_pixbytes = 0;
in_sizemove = 0;
fixup_prefs_dimensions (&currprefs);
if( !DirectDraw_Start() )
return 0;
if( DirectDraw_GetDisplayMode() != DD_OK )
return 0;
colortype = DirectDraw_GetPixelFormat();
write_log ("Ct: %08lx, picasso_vidinfo.selected_rgbformat %08lx\n", (unsigned long)colortype,
picasso_vidinfo.selected_rgbformat);
if (screen_is_picasso) {
fullscreen = currprefs.gfx_pfullscreen;
window_width = current_width = picasso_vidinfo.width;
window_height = current_height = picasso_vidinfo.height;
window_depth = current_depth = rgbformat_bits (picasso_vidinfo.selected_rgbformat);
} else {
fullscreen = currprefs.gfx_afullscreen;
window_width = current_width = currprefs.gfx_width;
window_height = current_height = currprefs.gfx_height;
window_depth = current_depth = (currprefs.color_mode == 0 ? 8
: currprefs.color_mode == 1 ? 15
: currprefs.color_mode == 2 ? 16
: currprefs.color_mode == 3 ? 8
: currprefs.color_mode == 4 ? 8 : 32);
}
//If screen depth is equal to the desired window_depth then no overlay is needed.
if( DirectDraw_GetSurfaceBitCount() == window_depth )
overlay = 0;
if (overlay) {
needs_direct = 1;
} else {
needs_direct = 0;
}
if (colortype == RGBFB_NONE && !overlay) {
needs_direct = 1;
fs_warning = "the desktop is running in an unknown color mode.";
} else if (colortype == RGBFB_CLUT && !overlay) {
needs_direct = 1;
fs_warning = "the desktop is running in 8 bit color depth, which UAE can't use in windowed mode.";
} else if ( !fullscreen && ( current_width >= DirectDraw_CurrentWidth() || current_height >= DirectDraw_CurrentHeight() ) ) {
needs_direct = 1;
fs_warning = "the desktop is too small for the specified window size.";
overlay = 0; // we're going to go full-screen
} else if (screen_is_picasso && !fullscreen &&
( picasso_vidinfo.selected_rgbformat != RGBFB_CHUNKY ) &&
( picasso_vidinfo.selected_rgbformat != colortype ) &&
overlay )
{
needs_direct = 1;
fs_warning = "you selected a Picasso display with a color depth different from that of the desktop and an overlay was unavailable.";
if( !doInit() )
{
overlay = 0; // we're going to go full-screen
// doInit in windowed-mode modifies the width/height params, so
// restore our mucked-up width and height values for full-screen.
window_width = current_width = picasso_vidinfo.width;
window_height = current_height = picasso_vidinfo.height;
}
DirectDraw_Release();
close_hwnds();
if( !DirectDraw_Start() )
return 0;
}
if( needs_direct && ! usedirect )
usedirect = needs_direct;
if( fs_warning && !overlay )
{
// Temporarily drop the DirectDraw stuff
DirectDraw_Release();
sprintf (tmpstr, "The selected screen mode can't be displayed in a window, because %s\n"
"Switching to full-screen display.", fs_warning);
MessageBox (0, tmpstr, "WinUAE", MB_ICONEXCLAMATION | MB_OK);
DirectDraw_Start();
fullscreen = 1;
}
if (! usedirect)
window_depth = rgbformat_bits (colortype);
if( current_depth == 24 )
{
if( screen_is_picasso )
fs_warning = "you've selected a Picasso display with a 24-bit depth, which WinUAE no longer supports.";
else
fs_warning = "the desktop is running in 24-bit color depth, which WinUAE no longer supports.";
/* Temporarily drop the DirectDraw stuff. This is necessary, otherwise
* WinNT will just return 1 for the message box without ever displaying
* it on the screen. */
DirectDraw_Release();
sprintf (tmpstr, "WinUAE cannot run because %s", fs_warning);
MessageBox (0, tmpstr, "WinUAE", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
if (! doInit ())
return 0;
if(!WIN32GFX_IsFullScreen() && ( bFirstTime || bJustClosedWithActiveMouse ) )
{
bFirstTime = FALSE;
bJustClosedWithActiveMouse = FALSE;
setmouseactive (1);
}
return 1;
}
int check_prefs_changed_gfx (void)
{
if (display_change_requested ||
( currprefs.gfx_afullscreen != changed_prefs.gfx_afullscreen ) ||
( currprefs.gfx_pfullscreen != changed_prefs.gfx_pfullscreen ) )
{
display_change_requested = 0;
currprefs.gfx_afullscreen = changed_prefs.gfx_afullscreen;
currprefs.gfx_pfullscreen = changed_prefs.gfx_pfullscreen;
close_windows ();
open_windows ();
return 1;
}
return 0;
}
/* Color management */
static xcolnr xcol8[4096];
static PALETTEENTRY colors256[256];
static int ncols256 = 0;
static int red_bits, green_bits, blue_bits;
static int red_shift, green_shift, blue_shift;
static int get_color (int r, int g, int b, xcolnr * cnp)
{
if (ncols256 == 256)
return 0;
colors256[ncols256].peRed = r * 0x11;
colors256[ncols256].peGreen = g * 0x11;
colors256[ncols256].peBlue = b * 0x11;
colors256[ncols256].peFlags = 0;
*cnp = ncols256;
ncols256++;
return 1;
}
static void init_colors (void)
{
int i;
HRESULT ddrval;
if (ncols256 == 0) {
alloc_colors256 (get_color);
memcpy (xcol8, xcolors, sizeof xcol8);
}
/* init colors */
switch( current_pixbytes )
{
case 1:
memcpy (xcolors, xcol8, sizeof xcolors);
ddrval = DirectDraw_SetPaletteEntries( 0, 256, colors256 );
if (ddrval != DD_OK)
gui_message ("DX_SetPalette() failed with %s/%d\n", DirectDraw_ErrorString (ddrval), ddrval);
break;
case 2:
case 3:
case 4:
red_bits = bits_in_mask( DirectDraw_GetPixelFormatBitMask( red_mask ) );
green_bits = bits_in_mask( DirectDraw_GetPixelFormatBitMask( green_mask ) );
blue_bits = bits_in_mask( DirectDraw_GetPixelFormatBitMask( blue_mask ) );
red_shift = mask_shift( DirectDraw_GetPixelFormatBitMask( red_mask ) );
green_shift = mask_shift( DirectDraw_GetPixelFormatBitMask( green_mask ) );
blue_shift = mask_shift( DirectDraw_GetPixelFormatBitMask( blue_mask ) );
alloc_colors64k (red_bits, green_bits, blue_bits, red_shift,
green_shift, blue_shift);
break;
}
switch (gfxvidinfo.pixbytes)
{
case 2:
for (i = 0; i < 4096; i++)
xcolors[i] = xcolors[i] * 0x00010001;
gfxvidinfo.can_double = 1;
break;
case 1:
for (i = 0; i < 4096; i++)
xcolors[i] = xcolors[i] * 0x01010101;
gfxvidinfo.can_double = 1;
break;
default:
gfxvidinfo.can_double = 0;
break;
}
}
int DX_FillResolutions (uae_u16 * ppixel_format)
{
struct win32_displaymode *dm;
int count = 0;
*ppixel_format = 0;
for (dm = win32_displaymode_list; dm != 0; dm = dm->next) {
*ppixel_format |= dm->colormodes;
if (dm->colormodes & RGBMASK_8BIT) {
DisplayModes[count].res.width = dm->width;
DisplayModes[count].res.height = dm->height;
DisplayModes[count].refresh = default_freq;
DisplayModes[count].depth = 1;
count++;
}
if (count >= MAX_PICASSO_MODES)
break;
if (dm->colormodes & (RGBMASK_16BIT | RGBMASK_15BIT)) {
DisplayModes[count].res.width = dm->width;
DisplayModes[count].res.height = dm->height;
DisplayModes[count].refresh = default_freq;
DisplayModes[count].depth = 2;
count++;
}
if (count >= MAX_PICASSO_MODES)
break;
if (dm->colormodes & RGBMASK_24BIT) {
DisplayModes[count].res.width = dm->width;
DisplayModes[count].res.height = dm->height;
DisplayModes[count].refresh = default_freq;
DisplayModes[count].depth = 3;
count++;
}
if (count >= MAX_PICASSO_MODES)
break;
if (dm->colormodes & RGBMASK_32BIT) {
DisplayModes[count].res.width = dm->width;
DisplayModes[count].res.height = dm->height;
DisplayModes[count].refresh = default_freq;
DisplayModes[count].depth = 4;
count++;
}
if (count >= MAX_PICASSO_MODES)
break;
}
return count;
}
void DX_SetPalette (int start, int count)
{
HRESULT ddrval;
if( !screen_is_picasso )
return;
if( picasso96_state.RGBFormat != RGBFB_CHUNKY )
{
/* notice_screen_contents_lost(); */
return;
}
if (picasso_vidinfo.pixbytes != 1)
{
/* write_log ("DX Setpalette emulation\n"); */
/* This is the case when we're emulating a 256 color display. */
while (count-- > 0)
{
int r = picasso96_state.CLUT[start].Red;
int g = picasso96_state.CLUT[start].Green;
int b = picasso96_state.CLUT[start].Blue;
picasso_vidinfo.clut[start++] = (doMask256 (r, red_bits, red_shift)
| doMask256 (g, green_bits, green_shift)
| doMask256 (b, blue_bits, blue_shift));
}
notice_screen_contents_lost();
return;
}
/* Set our DirectX palette here */
if( current_pixbytes == 1 )
{
ddrval = DirectDraw_SetPaletteEntries( start, count, (LPPALETTEENTRY)&(picasso96_state.CLUT[start] ) );
if (ddrval != DD_OK)
gui_message("DX_SetPalette() failed with %s/%d\n", DirectDraw_ErrorString (ddrval), ddrval);
}
else
{
write_log ("ERROR - DX_SetPalette() pixbytes %d\n", current_pixbytes );
}
}
void DX_Invalidate (int first, int last)
{
p96_double_buffer_first = first;
if( (unsigned)last >= picasso_vidinfo.height )
last = picasso_vidinfo.height - 1;
p96_double_buffer_last = last;
p96_double_buffer_needs_flushing = 1;
}
int DX_BitsPerCannon (void)
{
return 8;
}
static COLORREF BuildColorRef( int color, RGBFTYPE pixelformat )
{
COLORREF result;
/* Do special case first */
if( pixelformat == RGBFB_CHUNKY )
result = color;
else
result = do_get_mem_long( &color );
return result;
#if 0
int r,g,b;
write_log ( "DX_Blit() called to fill with color of 0x%x, rgbtype of 0x%x\n", color, pixelformat );
switch( pixelformat )
{
case RGBFB_R5G6B5PC:
r = color & 0xF800 >> 11;
g = color & 0x07E0 >> 5;
b = color & 0x001F;
break;
case RGBFB_R5G5B5PC:
r = color & 0x7C00 >> 10;
g = color & 0x03E0 >> 5;
b = color & 0x001F;
break;
case RGBFB_B5G6R5PC:
r = color & 0x001F;
g = color & 0x07E0 >> 5;
b = color & 0xF800 >> 11;
break;
case RGBFB_B5G5R5PC:
r = color & 0x001F;
g = color & 0x03E0 >> 5;
b = color & 0x7C00 >> 10;
break;
case RGBFB_B8G8R8:
r = color & 0x00FF0000 >> 16;
g = color & 0x0000FF00 >> 8;
b = color & 0x000000FF;
break;
case RGBFB_A8B8G8R8:
r = color & 0xFF000000 >> 24;
g = color & 0x00FF0000 >> 16;
b = color & 0x0000FF00 >> 8;
break;
case RGBFB_R8G8B8:
r = color & 0x000000FF;
g = color & 0x0000FF00 >> 8;
b = color & 0x00FF0000 >> 16;
break;
case RGBFB_A8R8G8B8:
r = color & 0x0000FF00 >> 8;
g = color & 0x00FF0000 >> 16;
b = color & 0xFF000000 >> 24;
break;
default:
write_log ( "Uknown 0x%x pixel-format\n", pixelformat );
break;
}
result = RGB(r,g,b);
write_log ( "R = 0x%02x, G = 0x%02x, B = 0x%02x - result = 0x%08x\n", r, g, b, result );
return result;
#endif
}
/* This is a general purpose DirectDrawSurface filling routine. It can fill within primary surface.
* Definitions:
* - primary is the displayed (visible) surface in VRAM, which may have an associated offscreen surface (or back-buffer)
*/
int DX_Fill( int dstx, int dsty, int width, int height, uae_u32 color, RGBFTYPE rgbtype )
{
int result = 0;
RECT dstrect;
RECT srcrect;
DDBLTFX ddbltfx;
memset( &ddbltfx, 0, sizeof( ddbltfx ) );
ddbltfx.dwFillColor = BuildColorRef( color, rgbtype );
ddbltfx.dwSize = sizeof( ddbltfx );
/* Set up our source rectangle. This NEVER needs to be adjusted for windowed display, since the
* source is ALWAYS in an offscreen buffer, or we're in full-screen mode. */
SetRect( &srcrect, dstx, dsty, dstx+width, dsty+height );
/* Set up our destination rectangle, and adjust for blit to windowed display (if necessary ) */
SetRect( &dstrect, dstx, dsty, dstx+width, dsty+height );
if( !fullscreen && !overlay )
OffsetRect( &dstrect, amigawin_rect.left, amigawin_rect.top );
/* Render our fill to the visible (primary) surface */
if( ( result = DirectDraw_Blt( primary_surface, &dstrect, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx ) ) )
{
if( DirectDraw_GetLockableType() == secondary_surface )
{
/* We've colour-filled the visible, but still need to colour-fill the offscreen */
result = DirectDraw_Blt( secondary_surface, &srcrect, invalid_surface, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx );
}
}
return result;
}
/* This is a general purpose DirectDrawSurface blitting routine. It can blit within primary surface
* Definitions:
* - primary is the displayed (visible) surface in VRAM, which may have an associated offscreen surface (or back-buffer)
*/
DDBLTFX fx = { sizeof( DDBLTFX ) };
DWORD BLIT_OPCODE_TRANSLATION[ BLIT_LAST ] =
{
BLACKNESS, /* BLIT_FALSE */
NOTSRCERASE,/* BLIT_NOR */
-1, /* BLIT_ONLYDST NOT SUPPORTED */
NOTSRCCOPY, /* BLIT_NOTSRC */
SRCERASE, /* BLIT_ONLYSRC */
DSTINVERT, /* BLIT_NOTDST */
SRCINVERT, /* BLIT_EOR */
-1, /* BLIT_NAND NOT SUPPORTED */
SRCAND, /* BLIT_AND */
-1, /* BLIT_NEOR NOT SUPPORTED */
-1, /* NO-OP */
MERGEPAINT, /* BLIT_NOTONLYSRC */
SRCCOPY, /* BLIT_SRC */
-1, /* BLIT_NOTONLYDST NOT SUPPORTED */
SRCPAINT, /* BLIT_OR */
WHITENESS /* BLIT_TRUE */
};
// This function is only called for full-screen Amiga screen-modes, and simply flips
// the front and back buffers. Additionally, because the emulation is not always drawing
// complete frames, we also need to update the back-buffer with the new contents we just
// flipped to. Thus, after our flip, we blit.
int DX_Flip( void )
{
int result = 0;
result = DirectDraw_Flip();
if( result )
{
result = DirectDraw_BltFast( secondary_surface, 0, 0, primary_surface, NULL );
}
return result;
}
int DX_Blit( int srcx, int srcy, int dstx, int dsty, int width, int height, BLIT_OPCODE opcode )
{
int result = 0;
RECT dstrect;
RECT srcrect;
DWORD dwROP = BLIT_OPCODE_TRANSLATION[ opcode ];
/* Set up our source rectangle. This NEVER needs to be adjusted for windowed display, since the
* source is ALWAYS in an offscreen buffer, or we're in full-screen mode. */
SetRect( &srcrect, srcx, srcy, srcx+width, srcy+height );
/* Set up our destination rectangle, and adjust for blit to windowed display (if necessary ) */
SetRect( &dstrect, dstx, dsty, dstx+width, dsty+height );
if( !fullscreen && !overlay )
OffsetRect( &dstrect, amigawin_rect.left, amigawin_rect.top );
if( dwROP == -1 )
{
/* Unsupported blit opcode! */
return 0;
}
else
{
fx.dwROP = dwROP;
}
/* Render our blit within the primary surface */
result = DirectDraw_Blt( primary_surface, &dstrect, DirectDraw_GetLockableType(), &srcrect, DDBLT_WAIT | DDBLT_ROP, &fx );
if( !result )
{
BLIT_OPCODE_TRANSLATION[ opcode ] = -1;
}
else if( DirectDraw_GetLockableType() == secondary_surface )
{
/* We've just blitted from the offscreen to the visible, but still need to blit from offscreen to offscreen
* NOTE: reset our destination rectangle again if its been modified above... */
if( ( srcx != dstx ) || ( srcy != dsty ) )
{
if( !fullscreen )
SetRect( &dstrect, dstx, dsty, dstx+width, dsty+height );
result = DirectDraw_Blt( secondary_surface, &dstrect, secondary_surface, &srcrect, DDBLT_WAIT | DDBLT_ROP, &fx );
}
}
return result;
}
void DX_WaitVerticalSync( void )
{
DirectDraw_WaitForVerticalBlank( DDWAITVB_BLOCKBEGIN );
}
uae_u32 DX_ShowCursor( uae_u32 activate )
{
uae_u32 result = 0;
if( ShowCursor( activate ) > 0 )
result = 1;
return result;
}
uae_u32 DX_MoveCursor( uae_u32 x, uae_u32 y )
{
uae_u32 result = 0;
// We may need to adjust the x,y values for our window-offset
if( !fullscreen )
{
RECT rect;
if( GetWindowRect( hAmigaWnd, &rect ) )
{
x = rect.left + x;
y = rect.top + y;
}
}
if( SetCursorPos( x, y ) )
result = 1;
return result;
}
static void open_screen( void )
{
close_windows ();
if( open_windows() )
DX_SetPalette (0, 256);
else
abort();
}
void gfx_set_picasso_state( int on )
{
if (screen_is_picasso == on)
return;
screen_is_picasso = on;
open_screen();
}
void gfx_set_picasso_modeinfo( int w, int h, int depth, int rgbfmt )
{
depth >>= 3;
if( ( picasso_vidinfo.width == w ) &&
( picasso_vidinfo.height == h ) &&
( picasso_vidinfo.depth == depth ) &&
( picasso_vidinfo.selected_rgbformat == rgbfmt) )
return;
picasso_vidinfo.selected_rgbformat = rgbfmt;
picasso_vidinfo.width = w;
picasso_vidinfo.height = h;
picasso_vidinfo.depth = depth;
picasso_vidinfo.extra_mem = 1;
if( screen_is_picasso )
{
open_screen();
}
}
int graphics_init (void)
{
return open_windows ();
}
int graphics_setup (void)
{
if( !DirectDraw_Start() )
return 0;
DirectDraw_Release();
InitPicasso96();
return 1;
}
void graphics_leave (void)
{
close_windows ();
dumpcustom ();
cleanup_modes ();
}
uae_u32 OSDEP_minimize_uae( void )
{
return ShowWindow( hAmigaWnd, SW_MINIMIZE );
}
static void close_windows (void)
{
gfxvidinfo.bufmem = 0;
releasecapture ();
setmouseactive (0);
ClipCursor (NULL);
DirectDraw_Release();
close_hwnds();
if( mouseactive )
bJustClosedWithActiveMouse = TRUE;
{
int i;
for( i=0;i<AK_CTRL+1;i++)my_kbd_handler (0,i,0);
for( i=0;i<AK_CTRL+1;i++)my_kbd_handler (i,0,0);
buttonstate[0] = 0;
buttonstate[1] = 0;
buttonstate[2] = 0;
}
bInitDone = FALSE; //?????JGI
overlay = 1; // Go back to desiring overlay support
}
void WIN32GFX_ToggleFullScreen( void )
{
if (needs_direct && !overlay)
return;
display_change_requested = 1;
if (screen_is_picasso)
currprefs.gfx_pfullscreen ^= 1;
else
currprefs.gfx_afullscreen ^= 1;
}
static int create_windows (void)
{
if (!fullscreen)
{
RECT rc;
LONG stored_x = 1, stored_y = GetSystemMetrics( SM_CYMENU ) + GetSystemMetrics( SM_CYBORDER );
DWORD regkeytype;
DWORD regkeysize = sizeof(LONG);
HLOCAL hloc;
LPINT lpParts;
RegQueryValueEx( hWinUAEKey, "xPos", 0, ®keytype, (LPBYTE)&stored_x, ®keysize );
RegQueryValueEx( hWinUAEKey, "yPos", 0, ®keytype, (LPBYTE)&stored_y, ®keysize );
if( stored_x < 1 )
stored_x = 1;
if( stored_y < ( GetSystemMetrics( SM_CYMENU ) + GetSystemMetrics( SM_CYBORDER ) ) )
stored_y = GetSystemMetrics( SM_CYMENU ) + GetSystemMetrics( SM_CYBORDER );
if( stored_x > GetSystemMetrics( SM_CXFULLSCREEN ) )
rc.left = 1;
else
rc.left = stored_x;
if( stored_y > GetSystemMetrics( SM_CYFULLSCREEN ) )
rc.top = 1;
else
rc.top = stored_y;
rc.right = rc.left + current_width;
rc.bottom = rc.top + current_height + GetSystemMetrics( SM_CYMENU ) + GetSystemMetrics( SM_CYBORDER )*3;
AdjustWindowRect (&rc, NORMAL_WINDOW_STYLE, FALSE);
hMainWnd = CreateWindowEx( picasso_on ? WS_EX_ACCEPTFILES : WS_EX_ACCEPTFILES | WS_EX_APPWINDOW, "PCsuxRox", "WinUAE",
NORMAL_WINDOW_STYLE, rc.left, rc.top,
rc.right - rc.left, rc.bottom - rc.top,
NULL, NULL, 0, NULL);
if (! hMainWnd)
return 0;
hStatusWnd = CreateStatusWindow (WS_CHILD | WS_VISIBLE, "", hMainWnd, 1);
if (hStatusWnd)
{
GetClientRect (hMainWnd, &rc);
/* Allocate an array for holding the right edge coordinates. */
hloc = LocalAlloc (LHND, sizeof (int) * NUM_PARTS);
if (hloc)
{
lpParts = LocalLock (hloc);
/* Calculate the right edge coordinate for each part, and copy the coords
* to the array. */
lpParts[0] = rc.right - (DRIVE_WIDTH * 4) - LED_WIDTH - FPS_WIDTH - 2;
lpParts[1] = lpParts[0] + FPS_WIDTH;
lpParts[2] = lpParts[1] + LED_WIDTH;
lpParts[3] = lpParts[2] + DRIVE_WIDTH;
lpParts[4] = lpParts[3] + DRIVE_WIDTH;
lpParts[5] = lpParts[4] + DRIVE_WIDTH;
lpParts[6] = lpParts[5] + DRIVE_WIDTH;
/* Create the seven parts */
SendMessage (hStatusWnd, SB_SETPARTS, (WPARAM) NUM_PARTS, (LPARAM) lpParts);
LocalUnlock (hloc);
LocalFree (hloc);
}
}
}
else
hMainWnd = NULL;
hAmigaWnd = CreateWindowEx (fullscreen ? WS_EX_TOPMOST : WS_EX_ACCEPTFILES | WS_EX_APPWINDOW,
"AmigaPowah", "WinUAE",
hMainWnd ? WS_VISIBLE | WS_CHILD : WS_VISIBLE | WS_POPUP,
hMainWnd ? 0 : CW_USEDEFAULT, hMainWnd ? 0 : CW_USEDEFAULT,
fullscreen ? GetSystemMetrics (SM_CXSCREEN) : current_width,
fullscreen ? GetSystemMetrics (SM_CYSCREEN) : current_height,
hMainWnd, NULL, 0, NULL);
if (! hAmigaWnd)
{
close_hwnds();
return 0;
}
if (hMainWnd)
UpdateWindow( hMainWnd );
if (hAmigaWnd)
UpdateWindow (hAmigaWnd);
return 1;
}
static void setoverlay(void)
{
RECT sr, dr, statusr;
POINT p = {0,0};
int maxwidth, maxheight;
GetClientRect(hMainWnd, &dr);
// adjust the dest-rect to avoid the status-bar
if( hStatusWnd )
{
if( GetWindowRect( hStatusWnd, &statusr ) )
dr.bottom = dr.bottom - ( statusr.bottom - statusr.top );
}
ClientToScreen( hMainWnd, &p );
dr.left = p.x;
dr.top = p.y;
dr.right += p.x;
dr.bottom += p.y;
sr.left = 0; sr.top = 0;
sr.right = current_width; sr.bottom = current_height;
// Adjust our dst-rect to match the dimensions of our src-rect
if( dr.right - dr.left > sr.right - sr.left )
{
dr.right = dr.left + sr.right - sr.left;
}
if( dr.bottom - dr.top > sr.bottom - sr.top )
{
dr.bottom = dr.top + sr.bottom - sr.top;
}
maxwidth = GetSystemMetrics(SM_CXSCREEN);
if (dr.right > maxwidth) {
sr.right = current_width - (dr.right - maxwidth);
dr.right = maxwidth;
}
maxheight = GetSystemMetrics(SM_CYSCREEN);
if (dr.bottom > maxheight) {
sr.bottom = current_height - (dr.bottom - maxheight);
dr.bottom = maxheight;
}
if (dr.left < 0) {
sr.left = -dr.left;
dr.left = 0;
}
if (dr.top < 0) {
sr.top = -dr.top;
dr.top = 0;
}
DirectDraw_UpdateOverlay(sr, dr);
}
static BOOL doInit (void)
{
if (! create_windows ())
goto oops;
if( screen_is_picasso )
{
if (! set_ddraw (current_width, current_height, fullscreen, overlay, window_depth,
(LPPALETTEENTRY) & picasso96_state.CLUT))
goto oops;
picasso_vidinfo.rowbytes = DirectDraw_GetSurfacePitch();
picasso_vidinfo.pixbytes = DirectDraw_GetBytesPerPixel();
picasso_vidinfo.rgbformat = DirectDraw_GetPixelFormat();
}
else
{
if (fullscreen)
{
#if 0
write_log ( "Calling adjust_screenmode with %d,%d,%d\n", window_width, window_height, window_depth );
if( WIN32GFX_AdjustScreenmode( &window_width, &window_height, &window_depth ) < 0 )
abort ();
write_log ( "Finished adjust_screenmode with %d,%d,%d\n", window_width, window_height, window_depth );
#endif
}
if (! set_ddraw (current_width, current_height, fullscreen, overlay, window_depth, colors256))
goto oops;
gfxvidinfo.bufmem = 0;
gfxvidinfo.linemem = 0;
gfxvidinfo.emergmem = scrlinebuf; // memcpy from system-memory to video-memory
gfxvidinfo.pixbytes = current_pixbytes;
gfxvidinfo.width = current_width;
gfxvidinfo.height = current_height;
gfxvidinfo.maxblocklines = 0; // flush_screen actually does everything
gfxvidinfo.rowbytes = DirectDraw_GetSurfacePitch();
}
if( fullscreen )
{
WIN32_MouseDefaults();
}
if( !DirectDraw_SurfaceLock( lockable_surface ) )
goto oops;
DirectDraw_SurfaceUnlock();
if( ( DirectDraw_GetPixelFormatFlags() & (DDPF_RGB | DDPF_PALETTEINDEXED8 | DDPF_RGBTOYUV ) ) )
{
write_log ( "%s mode (bits: %d, pixbytes: %d)\n", fullscreen ? "Full screen" : "Window",
DirectDraw_GetSurfaceBitCount(), current_pixbytes );
}
else
{
char szMessage[ MAX_PATH ];
WIN32GUI_LoadUIString( IDS_UNSUPPORTEDPIXELFORMAT, szMessage, MAX_PATH );
gui_message( szMessage);
goto oops;
}
init_colors ();
if (overlay)
setoverlay ();
#if 0 // This crashes WinXP, because that last param should be an LPWINDOWPOS...
if (! fullscreen)
SendMessage( hMainWnd, WM_WINDOWPOSCHANGED, 0, 0);
#endif
bInitDone = TRUE;
return 1;
oops:
DirectDraw_Release();
close_hwnds();
return 0;
}
void WIN32GFX_PaletteChange( void )
{
DirectDraw_SetPalette( 1 ); /* Remove current palette */
DirectDraw_SetPalette( 0 ); /* Set our real palette */
}
void WIN32GFX_ClearPalette( void )
{
DirectDraw_SetPalette( 1 ); /* Remove palette */
}
void WIN32GFX_SetPalette( void )
{
DirectDraw_SetPalette( 0 ); /* Set palette */
}
#endif
void WIN32GFX_WindowMove ( void )
{
if (overlay && hMainWnd && bInitDone) setoverlay();
}
void WIN32GFX_WindowSize ( void )
{
RECT r;
//?????JGI (to delete): if (!overlay) return;
if (!hMainWnd) return;
if(!GetClientRect (hMainWnd, &r)) return;
window_width = r.right - r.left;
window_height = r.bottom - r.top;
if (overlay && bInitDone) setoverlay();//????? JGI
}