Exemplo n.º 1
0
/**
 * create_gens_window_menubar(): Create the menu bar.
 */
void gens_window_create_menubar(void)
{
	if (gens_menu_bar != NULL)
	{
		// Menu bar already exists. Delete it.
		gtk_widget_destroy(gens_menu_bar);
		gens_menu_clear();
	}
	
	if (!vdraw_get_fullscreen() && Settings.showMenuBar)
	{
		// Create a menu bar.
		gens_menu_bar = gtk_menu_bar_new();
		gtk_widget_show(gens_menu_bar);
		gtk_box_pack_start(GTK_BOX(gens_vbox_main), gens_menu_bar, FALSE, FALSE, 0);
	}
	else
	{
		// Create a popup menu.
		gens_menu_bar = gtk_menu_new();
	}
	
	// Connect the menu "deactivate" signal.
	// For whatever reason, GtkMenuShell has a "deactivate" signal,
	// but not an "activate" signal.
	g_signal_connect((gpointer)gens_menu_bar, "deactivate",
			 G_CALLBACK(gens_menu_deactivate), NULL);
	
	// Accelerator Group.
	static GtkAccelGroup *gens_menu_accel_group = NULL;
	if (gens_menu_accel_group != NULL)
	{
		// Delete the accelerator group.
		gtk_window_remove_accel_group(GTK_WINDOW(gens_window), gens_menu_accel_group);
		g_object_unref(gens_menu_accel_group);
	}
	
	// Create an accelerator group.
	gens_menu_accel_group = gtk_accel_group_new();
	
	// Parse the menus.
	gens_menu_parse(&gmiMain[0], GTK_MENU_SHELL(gens_menu_bar), gens_menu_accel_group);
	
	// Add the accel group.
	gtk_window_add_accel_group(GTK_WINDOW(gens_window), gens_menu_accel_group);
	
	// Synchronize the menus.
	Sync_Gens_Window();
	
#ifdef GDK_WINDOWING_QUARTZ
	// Set the menu bar as the MacOS X menu bar.
	if (!vdraw_get_fullscreen() && Settings.showMenuBar)
		ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(gens_menu_bar));
#endif
}
Exemplo n.º 2
0
/**
 * create_gens_window_menubar(): Create the menu bar.
 */
void gens_window_create_menubar(void)
{
	if (gens_menu_bar != NULL)
	{
		// Menu bar already exists. Delete it.
		gtk_widget_destroy(gens_menu_bar);
		gens_menu_clear();
	}
	
	if (!vdraw_get_fullscreen() && Settings.showMenuBar)
	{
		// Create a menu bar.
		gens_menu_bar = gtk_menu_bar_new();
		gtk_widget_show(gens_menu_bar);
		gtk_box_pack_start(GTK_BOX(gens_vbox_main), gens_menu_bar, FALSE, FALSE, 0);
	}
	else
	{
		// Create a popup menu.
		gens_menu_bar = gtk_menu_new();
	}
	
	// Accelerator Group.
	static GtkAccelGroup *gens_menu_accel_group = NULL;
	if (gens_menu_accel_group != NULL)
	{
		// Delete the accelerator group.
		gtk_window_remove_accel_group(GTK_WINDOW(gens_window), gens_menu_accel_group);
		g_object_unref(gens_menu_accel_group);
	}
	
	// Create an accelerator group.
	gens_menu_accel_group = gtk_accel_group_new();
	
	// Parse the menus.
	gens_menu_parse(&gmiMain[0], gens_menu_bar, gens_menu_accel_group);
	
	// Add the accel group.
	gtk_window_add_accel_group(GTK_WINDOW(gens_window), gens_menu_accel_group);
	
	// Synchronize the menus.
	Sync_Gens_Window();
	
#ifdef GDK_WINDOWING_QUARTZ
	// Set the menu bar as the MacOS X menu bar.
	if (!vdraw_get_fullscreen() && Settings.showMenuBar)
		ige_mac_menu_set_menu_bar(GTK_MENU_SHELL(gens_menu_bar));
#endif
}
Exemplo n.º 3
0
/**
 * vdraw_ddraw_set_cooperative_level(): Sets the DirectDraw cooperative level.
 * @return 0 on success; non-zero on error.
 */
int WINAPI vdraw_ddraw_set_cooperative_level(void)
{
	if (!gens_window || !lpDD)
		return -1;
	
	HRESULT rval;
#ifdef DISABLE_EXCLUSIVE_FULLSCREEN_LOCK
	Video.VSync_FS = 0;
	rval = lpDD->SetCooperativeLevel(gens_window, DDSCL_NORMAL);
#else
	if (vdraw_get_fullscreen())
		rval = lpDD->SetCooperativeLevel(gens_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
	else
		rval = lpDD->SetCooperativeLevel(gens_window, DDSCL_NORMAL);
#endif
	
	if (FAILED(rval))
	{
		LOG_MSG(video, LOG_MSG_LEVEL_WARNING,
			"lpDD->SetCooperativeLevel() failed.");
		// TODO: Error handling code.
	}
	else
	{
		LOG_MSG(video, LOG_MSG_LEVEL_INFO,
			"lpDD->SetCooperativeLevel() succeeded.");
	}
	
	return 0;
}
Exemplo n.º 4
0
/**
 * vdraw_ddraw_adjust_RectDest(): Adjust RectDest.
 * @return
 */
void WINAPI vdraw_ddraw_adjust_RectDest(void)
{
	if (vdraw_get_fullscreen())
	{
		// Fullscreen.
		RectDest.left = 0;
		RectDest.top = 0;
		RectDest.right = Res_X;
		RectDest.bottom = Res_Y;
		
		// Clear the scrDiff rectangle.
		memset(&RectDest_scrDiff, 0, sizeof(RectDest_scrDiff));
		return;
	}
	
	// Windowed. Get the window size.
	GetClientRect(gens_window, &RectDest);
	
	// Adjust the destination rectangle for the window position.
	POINT p = {0, 0};
	ClientToScreen(gens_window, &p);
	RectDest.top += p.y;
	RectDest.bottom += p.y;
	RectDest.left += p.x;
	RectDest.right += p.x;
	
	// Clip the destination rectangle to the screen.
	// TODO: Update for 2x hardware rendering (if we do that eventually).
	memset(&RectDest_scrDiff, 0, sizeof(RectDest_scrDiff));
	int diff;
	if (RectDest.bottom > vdraw_rectDisplay.bottom)
	{
		// Off the bottom of the screen.
		diff = (vdraw_rectDisplay.bottom - RectDest.bottom);
		RectDest.bottom += diff;
		RectDest_scrDiff.bottom = diff;
	}
	if (RectDest.top < vdraw_rectDisplay.top)
	{
		// Off the top of the screen.
		diff = (vdraw_rectDisplay.top - RectDest.top);
		RectDest.top += diff;
		RectDest_scrDiff.top = diff;
	}
	if (RectDest.left <= vdraw_rectDisplay.left)
	{
		// Off the left side of the screen.
		diff = (vdraw_rectDisplay.left - RectDest.left);
		RectDest.left += diff;
		RectDest_scrDiff.left = diff;
	}
	if (RectDest.right > vdraw_rectDisplay.right)
	{
		// Off the right side of the screen.
		diff = (vdraw_rectDisplay.right - RectDest.right);
		RectDest.right += diff;
		RectDest_scrDiff.right = diff;
	}
}
Exemplo n.º 5
0
/**
 * gens_window_create_menubar(): Create the menu bar.
 */
void gens_window_create_menubar(void)
{
	if (MainMenu)
	{
		// Menu bar already exists. Delete it.
		DestroyMenu(MainMenu);
		gens_menu_clear();
	}
	
	DestroyMenu(MainMenu);
	
	// Create the main menu.
	if (!vdraw_get_fullscreen() && Settings.showMenuBar)
	{
		// Create a menu bar.
		MainMenu = CreateMenu();
	}
	else
	{
		// Create a popup menu.
		MainMenu = CreatePopupMenu();
	}
	
	// Parse the menus.
	gens_menu_parse(&gmiMain[0], MainMenu);
	
	// Synchronize the menus.
	Sync_Gens_Window();
	
	// Set the menu bar.
	if (!vdraw_get_fullscreen() && Settings.showMenuBar)
		SetMenu(gens_window, MainMenu);
	else
		SetMenu(gens_window, NULL);
	
	if (!vdraw_get_fullscreen())
	{
		// Resize the window after the menu bar is rebuilt.
		if (vdraw_scale <= 0)
			return;
		const int w = 320 * vdraw_scale;
		const int h = 240 * vdraw_scale;
		gsft_win32_set_actual_window_size(gens_window, w, h);
	}
}
Exemplo n.º 6
0
/**
 * gens_window_reinit(): Reinitialize the Gens window.
 */
void gens_window_reinit(void)
{
	// Determine the window size using the scaling factor.
	if (vdraw_scale <= 0)
		return;
	const int w = 320 * vdraw_scale;
	const int h = 240 * vdraw_scale;
	
	LONG_PTR lStyle;
	
	if (vdraw_get_fullscreen())
	{
		// Fullscreen. Hide the mouse cursor and the window borders.
		while (ShowCursor(TRUE) < 1) { }
		while (ShowCursor(FALSE) >= 0) { }
		
		// Hide the window borders.
		lStyle = GetWindowLongPtr(gens_window, GWL_STYLE);
		lStyle &= ~(WS_POPUPWINDOW | WS_OVERLAPPEDWINDOW);
		SetWindowLongPtr(gens_window, GWL_STYLE, lStyle);
		SetWindowPos(gens_window, NULL, 0, 0, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
	}
	else
	{
		// Windowed. Show the mouse cursor and the window borders.
		while (ShowCursor(FALSE) >= 0) { }
		while (ShowCursor(TRUE) < 1) { }
		
		// Adjust the window style.
		lStyle = GetWindowLongPtr(gens_window, GWL_STYLE);
		if (vdraw_cur_backend_flags & VDRAW_BACKEND_FLAG_WINRESIZE)
		{
			// Backend supports resizable windows.
			lStyle &= ~WS_POPUPWINDOW;
			lStyle |= WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE | WS_CLIPSIBLINGS;
		}
		else
		{
			// Backend does not support resizable windows.
			lStyle &= ~WS_OVERLAPPEDWINDOW;
			lStyle |= WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE | WS_CLIPSIBLINGS;
		}
		SetWindowLongPtr(gens_window, GWL_STYLE, lStyle);
		
		// Reposition the window.
		SetWindowPos(gens_window, NULL, Window_Pos.x, Window_Pos.y, 0, 0,
			     SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
	}
	
	// Rebuild the menu bar.
	// This is needed if the mode is switched from windowed to fullscreen, or vice-versa.
	gens_window_create_menubar();
	
	// Synchronize menus.
	Sync_Gens_Window();
}
Exemplo n.º 7
0
/**
 * vdraw_ddraw_restore_primary(): Restore the primary DirectDraw surface.
 * @return 0 on success; non-zero on error.
 */
int WINAPI vdraw_ddraw_restore_primary(void)
{
	if (!lpDD)
		return -1;
	
	if (vdraw_get_fullscreen() && Video.VSync_FS)
	{
		while (lpDDS_Primary->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_SURFACEBUSY) { }
		lpDD->FlipToGDISurface();
	}
	
	return 0;
}
Exemplo n.º 8
0
//#include "plugins/render/double/mdp_render_2x_plugin.h"
static bool WINAPI vdraw_ddraw_is_hw_render(void)
{
	if (vdraw_get_sw_render())
		return false;
	
	// Check the renderer.
	mdp_render_fn cur_render = (vdraw_get_fullscreen() ? vdraw_blitFS : vdraw_blitW);
	if (cur_render == mdp_render_1x_render_t.blit)
		return true;
	//else if (cur_render == mdp_render_2x_render_t.blit)
	//	return true;
	
	return false;
}
Exemplo n.º 9
0
/**
 * vdraw_ddraw_flip(): Flip the screen buffer. [Called by vdraw_flip().]
 * @return 0 on success; non-zero on error.
 */
int vdraw_ddraw_flip(void)
{
	if (!lpDD)
		return -1;
	
	HRESULT rval = DD_OK;
	DDSURFACEDESC2 ddsd;
	ddsd.dwSize = sizeof(ddsd);
	RECT RectSrc;
	
	// Calculate the source rectangle.
	vdraw_ddraw_calc_RectSrc(RectSrc);
	
	if (vdraw_get_fullscreen())
	{
		// Fullscreen.
		if (vdraw_ddraw_is_hw_render())
		{
			// Hardware rendering.
			
			// 1x rendering.
			// TODO: Test this with border color stuff.
			// Wine doesn't seem to have a 320x240 fullscreen mode available...
			// TODO: Test this on a system that supports 1x in fullscreen on DirectDraw.
			
			vdraw_ddraw_draw_text(&ddsd, lpDDS_Back, true);
			if (Video.VSync_FS)
			{
				lpDDS_Flip->Blt(&RectDest, lpDDS_Back, &RectSrc, DDBLT_WAIT | DDBLT_ASYNC, NULL);
				lpDDS_Primary->Flip(NULL, DDFLIP_WAIT);
			}
			else
			{
				lpDDS_Primary->Blt(&RectDest, lpDDS_Back, &RectSrc, DDBLT_WAIT | DDBLT_ASYNC, NULL);
				//lpDDS_Primary->Blt(&RectDest, lpDDS_Back, &RectSrc, NULL, NULL);
			}
		}
		else
		{
			// Software rendering.
			LPDIRECTDRAWSURFACE7 curBlit = lpDDS_Blit;
			rval = curBlit->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
			
			if (FAILED(rval))
				goto cleanup_flip;
			
			vdraw_rInfo.destScreen = (void*)ddsd.lpSurface;
			vdraw_rInfo.width = 320;
			vdraw_rInfo.height = 240;
			vdraw_rInfo.destPitch = ddsd.lPitch;
			
			if (vdraw_needs_conversion)
			{
				// Color depth conversion is required.
				vdraw_rgb_convert(&vdraw_rInfo);
			}
			else
			{
				// Color conversion is not required.
				vdraw_blitFS(&vdraw_rInfo);
			}
			
			// Draw the text.
			vdraw_ddraw_draw_text(&ddsd, curBlit, false);
			
			curBlit->Unlock(NULL);
			
			if (curBlit == lpDDS_Back) // note: this can happen in windowed fullscreen, or if CORRECT_256_ASPECT_RATIO is defined and the current display mode is 256 pixels across
			{
				if (Video.VSync_FS)
				{
					int vb;
					lpDD->GetVerticalBlankStatus(&vb);
					if (!vb)
						lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
				}
				
				lpDDS_Primary->Blt(&RectDest, lpDDS_Back, &RectSrc, DDBLT_WAIT | DDBLT_ASYNC, NULL);
			}
			else
			{
				if (Video.VSync_FS)
				{
					lpDDS_Primary->Flip(NULL, DDFLIP_WAIT);
				}
			}
		}
	}
	else
	{
		// Windowed mode.
		if (!vdraw_ddraw_is_hw_render())
		{
			rval = lpDDS_Blit->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
			
			if (FAILED(rval))
				goto cleanup_flip;
			
			vdraw_rInfo.destScreen = (void*)ddsd.lpSurface;
			vdraw_rInfo.width = 320;
			vdraw_rInfo.height = 240;
			vdraw_rInfo.destPitch = ddsd.lPitch;
			
			if (vdraw_needs_conversion)
			{
				// Color depth conversion is required.
				vdraw_rgb_convert(&vdraw_rInfo);
			}
			else
			{
				// Color conversion is not required.
				vdraw_blitW(&vdraw_rInfo);
			}
			
			// Draw the text.
			vdraw_ddraw_draw_text(&ddsd, lpDDS_Blit, false);
			
			lpDDS_Blit->Unlock(NULL);
		}
		else
		{
			// Draw the text.
			vdraw_ddraw_draw_text(&ddsd, lpDDS_Blit, true);
		}
		
		if (RectDest.top < RectDest.bottom)
		{
			if (Video.VSync_W)
			{
				int vb;
				lpDD->GetVerticalBlankStatus(&vb);
				if (!vb)
					lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
			}
			
			// Blit the image.
			rval = lpDDS_Primary->Blt(&RectDest, lpDDS_Back, &RectSrc, DDBLT_WAIT | DDBLT_ASYNC, NULL);
			//rval = lpDDS_Primary->Blt(&RectDest, lpDDS_Back, &RectSrc, NULL, NULL);
		}
	}

cleanup_flip:
	if (rval == DDERR_SURFACELOST)
		rval = vdraw_ddraw_restore_graphics();
	
	return 1;
}
Exemplo n.º 10
0
/**
 * vdraw_ddraw_clear_primary_screen(): Clear the primary screen.
 * @return 0 on success; non-zero on error.
 */
int WINAPI vdraw_ddraw_clear_primary_screen(void)
{
	if (!lpDD || !lpDDS_Primary)
		return -1;
	
	DDSURFACEDESC2 ddsd;
	DDBLTFX ddbltfx;
	RECT rd;
	POINT p;
	
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	
	memset(&ddbltfx, 0, sizeof(ddbltfx));
	ddbltfx.dwSize = sizeof(ddbltfx);
	ddbltfx.dwFillColor = 0; // Black
	
	if (vdraw_get_fullscreen())
	{
		if (Video.VSync_FS)
		{
			lpDDS_Flip->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx);
			lpDDS_Primary->Flip(NULL, DDFLIP_WAIT);
			
			lpDDS_Flip->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx);
			lpDDS_Primary->Flip(NULL, DDFLIP_WAIT);
			
			lpDDS_Flip->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx);
			lpDDS_Primary->Flip(NULL, DDFLIP_WAIT);
		}
		else
		{
			lpDDS_Primary->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx);
		}
	}
	else
	{
		p.x = p.y = 0;
		GetClientRect(gens_window, &rd);
		ClientToScreen(gens_window, &p);
		
		rd.left = p.x;
		rd.top = p.y;
		rd.right += p.x;
		rd.bottom += p.y;
		
		// Clip the destination rectangle to the screen.
		if (rd.bottom > vdraw_rectDisplay.bottom)
			rd.bottom += (vdraw_rectDisplay.bottom - rd.bottom);
		if (rd.top < vdraw_rectDisplay.top)
			rd.top += (vdraw_rectDisplay.top - rd.top);
		if (rd.left < vdraw_rectDisplay.left)
			rd.left += (vdraw_rectDisplay.left - rd.left);
		if (rd.right > vdraw_rectDisplay.right)
			rd.right += (vdraw_rectDisplay.right - rd.right);
		
		if (rd.top < rd.bottom)
			lpDDS_Primary->Blt(&rd, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx);
	}
	
	return 0;
}
Exemplo n.º 11
0
/**
 * vdraw_ddraw_init(): Initialize the DirectDraw video subsystem.
 * @return 0 on success; non-zero on error.
 */
int vdraw_ddraw_init(void)
{
	DDSURFACEDESC2 ddsd;
	
	vdraw_ddraw_end();
	
	mdp_render_t *rendMode = get_mdp_render_t();
	const int scale = rendMode->scale;
	
	// Determine the window size using the scaling factor.
	if (scale <= 0)
		return -1;
	const int w = 320 * scale;
	const int h = 240 * scale;
	
	if (vdraw_get_fullscreen())
	{
		Res_X = w;
		Res_Y = h;
	}
	
	// Return value.
	int rval;
	
	// Initialize DirectDraw.
	// TODO: Initialize DirectDraw on the monitor with most of Gens/GS onscreen.
	LPDIRECTDRAW lpDD_Init;
	rval = DirectDrawCreate(NULL, &lpDD_Init, NULL);
	if (FAILED(rval))
	{
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"DirectDrawCreate() failed: 0x%08X", rval);
		return -2;
	}
	
	rval = lpDD_Init->QueryInterface(IID_IDirectDraw7, (LPVOID*)&lpDD);
	if (FAILED(rval))
	{
		if (lpDD_Init)
			lpDD_Init->Release();
		
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"lpDD_Init->QueryInterface(IID_IDirectDraw4) failed: 0x%08X", rval);
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"This can usually be fixed by upgrading DirectX.");
		return -3;
	}
	
	// Free the DirectDraw initialization object.
	lpDD_Init->Release();
	
	// Set the cooperative level.
	vdraw_ddraw_set_cooperative_level();
	
	// TODO: 15-bit color override. ("Force 555" or "Force 565" in the config file.)
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	
	// TODO: Figure out what FS_No_Res_Change is for.
	// TODO: Figure out if this is correct.
	if (vdraw_get_fullscreen() /* && !FS_No_Res_Change*/)
	{
		// Use the color depth setting.
		// NOTE: "15-bit" color requires 16-bit to be specified.
		rval = lpDD->SetDisplayMode(Res_X, Res_Y, (bppOut == 15 ? 16 : bppOut), 0, 0);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->SetDisplayMode() failed: 0x%08X", rval);
			
			// If render mode is set to Normal, try using Double instead.
			if (rendMode_FS == RenderMgr::begin() && rendMode_FS != RenderMgr::end())
			{
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"Renderer is set to Normal; attempting to use Double instead.");
				rendMode_FS++;
				vdraw_set_renderer(rendMode_FS);
				vdraw_text_write("Normal rendering failed. Using Double.", 1500);
				Sync_Gens_Window_GraphicsMenu();
			}
			
			return -4;
		}
	}
	
#if 0
	// Check the current color depth.
	unsigned char newBpp;
	lpDD->GetDisplayMode(&ddsd);
	switch (ddsd.ddpfPixelFormat.dwGBitMask)
	{
		case 0x03E0:
			// 15-bit color.
			newBpp = 15;
			break;
		case 0x07E0:
			// 16-bit color.
			newBpp = 16;
			break;
		case 0x00FF00:
		default:
			// 32-bit color.
			newBpp = 32;
			break;
	}
	
	if (newBpp != bppOut)
		vdraw_set_bpp(newBpp, false);
#endif
	
	// Clear ddsd.
	memset(&ddsd, 0x00, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	
	if (vdraw_get_fullscreen() && Video.VSync_FS)
	{
		ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
		ddsd.dwBackBufferCount = 2;
	}
	else
	{
		ddsd.dwFlags = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	}
	
	// Create the primary surface.
	rval = lpDD->CreateSurface(&ddsd, &lpDDS_Primary, NULL);
	if (FAILED(rval))
	{
		vdraw_ddraw_free_all(false);
		LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
			"lpDD->CreateSurface(&lpDDS_Primary) failed: 0x%08X", rval);
		return -5;
	}
	
	if (vdraw_get_fullscreen())
	{
		if (Video.VSync_FS)
		{
			ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
			
			rval = lpDDS_Primary->GetAttachedSurface(&ddsd.ddsCaps, &lpDDS_Flip);
			if (FAILED(rval))
			{
				vdraw_ddraw_free_all(false);
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"lpDDS_Primary->GetAttachSurface() failed: 0x%08X", rval);
				return -6;
			}
			
			lpDDS_Blit = lpDDS_Flip;
		}
		else
		{
			lpDDS_Blit = lpDDS_Primary;
		}
	}
	else
	{
		rval = lpDD->CreateClipper(0, &lpDDC_Clipper, NULL);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateClipper() failed: 0x%08X", rval);
			return -7;
		}
		
		rval = lpDDC_Clipper->SetHWnd(0, gens_window);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDC_Clipper->SetHWnd() failed: 0x%08X", rval);
			return -8;
		}
		
		rval = lpDDS_Primary->SetClipper(lpDDC_Clipper);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDC_Primary->SetClipper() failed: 0x%08X", rval);
			return -9;
		}
	}
	
	// Clear ddsd again.
	memset(&ddsd, 0, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	
	// Determine the width and height.
	// NOTE: For DirectDraw, the actual 336 width is used.
	if (vdraw_ddraw_is_hw_render())
	{
		// Normal render mode. 320x240 [336x240]
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
		ddsd.dwWidth = 336;
		ddsd.dwHeight = 240;
	}
	else
	{
		// Larger than 1x.
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
		ddsd.dwWidth = w;
		ddsd.dwHeight = h;
	}
	
	// Set the pixel format.
	ddsd.dwFlags |= DDSD_PIXELFORMAT;
	ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
	ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
	ddsd.ddpfPixelFormat.dwFourCC = 0; // RGB
	ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
	
	// Bits per component.
	switch (bppOut)
	{
		case 15:
			// 15-bit color. (555)
			ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
			ddsd.ddpfPixelFormat.dwRBitMask = 0x7C00;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x03E0;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
			break;
		
		case 16:
			// 16-bit color. (555)
			ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
			ddsd.ddpfPixelFormat.dwRBitMask = 0xF800;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x07E0;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
			break;
		
		case 32:
		default:
			// 32-bit color.
			ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
			ddsd.ddpfPixelFormat.dwRBitMask = 0xFF0000;
			ddsd.ddpfPixelFormat.dwGBitMask = 0x00FF00;
			ddsd.ddpfPixelFormat.dwBBitMask = 0x0000FF;
			break;
	}
	
	// Create the back surface.
	rval = lpDD->CreateSurface(&ddsd, &lpDDS_Back, NULL);
	if (FAILED(rval))
	{
		// Failed to create the back surface.
		// If we attempted to create it in video memory, try system memory instead.
		if (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
		{
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_VIDEOMEMORY) failed: 0x%08X", rval);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"Attempting to use DDSCAPS_SYSTEMMEMORY instead.");
			ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
			ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
			rval = lpDD->CreateSurface(&ddsd, &lpDDS_Back, NULL);
			if (FAILED(rval))
			{
				// Failed to create the back surface in system memory.
				vdraw_ddraw_free_all(false);
				LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
					"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_SYSTEMMEMORY) failed: 0x%08X", rval);
				return -10;
			}
		}
		else
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDD->CreateSurface(&lpDDS_Back, DDSCAPS_SYSTEMMEMORY) failed: 0x%08X", rval);
			return -11;
		}
	}
	
	// TODO: Check if this is right.
	// I think this might be causing the frame counter flicker in full screen mode.
	//if (!vdraw_get_fullscreen() || (rendMode >= 1 && (/*FS_No_Res_Change ||*/ Res_X != 640 || Res_Y != 480)))
	if (!vdraw_get_fullscreen() || !vdraw_ddraw_is_hw_render())
		lpDDS_Blit = lpDDS_Back;
	
	if (vdraw_ddraw_is_hw_render())
	{
		// Normal rendering mode uses MD_Screen directly.
		memset(&ddsd, 0, sizeof(ddsd));
		ddsd.dwSize = sizeof(ddsd);
		
		// TODO: This causes issues if the selected color depth isn't the
		// same as the desktop color depth. This only affects windowed mode,
		// since in fullscreen, the desktop color depth is changed.
		rval = lpDDS_Back->GetSurfaceDesc(&ddsd);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDS_Back->GetSurfaceDesc() failed: 0x%08X", rval);
			return -12;
		}
		
		ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
		ddsd.dwWidth = 336;
		ddsd.dwHeight = 240;
		
		if (ddsd.ddpfPixelFormat.dwRGBBitCount > 16)
		{
			// 32-bit color.
			ddsd.lpSurface = MD_Screen.u32;
			ddsd.lPitch = 336 * 4;
		}
		else
		{
			// 15-bit or 16-bit color.
			ddsd.lpSurface = MD_Screen.u16;
			ddsd.lPitch = 336 * 2;
		}
		
		rval = lpDDS_Back->SetSurfaceDesc(&ddsd, 0);
		if (FAILED(rval))
		{
			vdraw_ddraw_free_all(false);
			LOG_MSG(video, LOG_MSG_LEVEL_ERROR,
				"lpDDS_Back->SetSurfaceDesc() failed: 0x%08X", rval);
			return -13;
		}
	}
	
	// Initialize the destination rectangle.
	vdraw_ddraw_adjust_RectDest();
	
	// Reset the render mode.
	vdraw_reset_renderer(false);
	
	// Synchronize menus.
	Sync_Gens_Window();
	
	// vdraw_ddraw initialized.
	return 0;
}