//============================================================
//
//  drawgdi.c - Win32 GDI drawing
//
//  Copyright Nicola Salmoria and the MAME Team.
//  Visit http://mamedev.org for licensing and usage restrictions.
//
//============================================================

// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

// MAME headers
#include "mamecore.h"
#include "restrack.h"

// MAMEOS headers
#include "window.h"



//============================================================
//  TYPE DEFINITIONS
//============================================================

/* gdi_info is the information for the current screen */
typedef struct _gdi_info gdi_info;
struct _gdi_info
{
	BITMAPINFO				bminfo;
	RGBQUAD					colors[256];
	UINT8 *					bmdata;
	size_t					bmsize;
};



//============================================================
//  PROTOTYPES
//============================================================

// core functions
static void drawgdi_exit(void);
static int drawgdi_window_init(win_window_info *window);
static void drawgdi_window_destroy(win_window_info *window);
static const render_primitive_list *drawgdi_window_get_primitives(win_window_info *window);
static int drawgdi_window_draw(win_window_info *window, HDC dc, int update);

// rendering
static void drawgdi_rgb888_draw_primitives(const render_primitive *primlist, void *dstdata, UINT32 width, UINT32 height, UINT32 pitch);



//============================================================
//  drawgdi_init
//============================================================

int drawgdi_init(win_draw_callbacks *callbacks)
{
	// fill in the callbacks
	callbacks->exit = drawgdi_exit;
	callbacks->window_init = drawgdi_window_init;
	callbacks->window_get_primitives = drawgdi_window_get_primitives;
	callbacks->window_draw = drawgdi_window_draw;
	callbacks->window_destroy = drawgdi_window_destroy;
	return 0;
}



//============================================================
//  drawgdi_exit
//============================================================

static void drawgdi_exit(void)
{
}



//============================================================
//  drawgdi_window_init
//============================================================

static int drawgdi_window_init(win_window_info *window)
{
	gdi_info *gdi;
	int i;

	// allocate memory for our structures
	gdi = alloc_clear_or_die(gdi_info);
	window->drawdata = gdi;

	// fill in the bitmap info header
	gdi->bminfo.bmiHeader.biSize			= sizeof(gdi->bminfo.bmiHeader);
	gdi->bminfo.bmiHeader.biPlanes			= 1;
	gdi->bminfo.bmiHeader.biCompression		= BI_RGB;
	gdi->bminfo.bmiHeader.biSizeImage		= 0;
	gdi->bminfo.bmiHeader.biXPelsPerMeter	= 0;
	gdi->bminfo.bmiHeader.biYPelsPerMeter	= 0;
	gdi->bminfo.bmiHeader.biClrUsed			= 0;
	gdi->bminfo.bmiHeader.biClrImportant	= 0;

	// initialize the palette to a gray ramp
	for (i = 0; i < 256; i++)
	{
		gdi->bminfo.bmiColors[i].rgbRed			= i;
		gdi->bminfo.bmiColors[i].rgbGreen		= i;
		gdi->bminfo.bmiColors[i].rgbBlue		= i;
		gdi->bminfo.bmiColors[i].rgbReserved	= i;
	}

	return 0;
}



//============================================================
//  drawgdi_window_destroy
//============================================================

static void drawgdi_window_destroy(win_window_info *window)
{
	gdi_info *gdi = (gdi_info *)window->drawdata;

	// skip if nothing
	if (gdi == NULL)
		return;

	// free the bitmap memory
	if (gdi->bmdata != NULL)
		free(gdi->bmdata);
	free(gdi);
	window->drawdata = NULL;
}



//============================================================
//  drawgdi_window_get_primitives
//============================================================

static const render_primitive_list *drawgdi_window_get_primitives(win_window_info *window)
{
	RECT client;
	GetClientRect(window->hwnd, &client);
	render_target_set_bounds(window->target, rect_width(&client), rect_height(&client), winvideo_monitor_get_aspect(window->monitor));
	return render_target_get_primitives(window->target);
}



//============================================================
//  drawgdi_window_draw
//============================================================

static int drawgdi_window_draw(win_window_info *window, HDC dc, int update)
{
	gdi_info *gdi = (gdi_info *)window->drawdata;
	int width, height, pitch;
	RECT bounds;

	// we don't have any special resize behaviors
	if (window->resize_state == RESIZE_STATE_PENDING)
		window->resize_state = RESIZE_STATE_NORMAL;

	// get the target bounds
	GetClientRect(window->hwnd, &bounds);

	// compute width/height/pitch of target
	width = rect_width(&bounds);
	height = rect_height(&bounds);
	pitch = (width + 3) & ~3;

	// make sure our temporary bitmap is big enough
	if (pitch * height * 4 > gdi->bmsize)
	{
		gdi->bmsize = pitch * height * 4 * 2;
		gdi->bmdata = (UINT8 *)realloc(gdi->bmdata, gdi->bmsize);
	}

	// draw the primitives to the bitmap
	osd_lock_acquire(window->primlist->lock);
	drawgdi_rgb888_draw_primitives(window->primlist->head, gdi->bmdata, width, height, pitch);
	osd_lock_release(window->primlist->lock);

	// fill in bitmap-specific info
	gdi->bminfo.bmiHeader.biWidth = pitch;
	gdi->bminfo.bmiHeader.biHeight = -height;
	gdi->bminfo.bmiHeader.biBitCount = 32;

	// blit to the screen
	StretchDIBits(dc, 0, 0, width, height,
				0, 0, width, height,
				gdi->bmdata, &gdi->bminfo, DIB_RGB_COLORS, SRCCOPY);
	return 0;
}



//============================================================
//  SOFTWARE RENDERING
//============================================================

#define FUNC_PREFIX(x)		drawgdi_rgb888_##x
#define PIXEL_TYPE			UINT32
#define SRCSHIFT_R			0
#define SRCSHIFT_G			0
#define SRCSHIFT_B			0
#define DSTSHIFT_R			16
#define DSTSHIFT_G			8
#define DSTSHIFT_B			0

#include "rendersw.c"
