//============================================================
//
//  drawgdi.c - Win32 GDI drawing
//
//============================================================
//
//  Copyright Aaron Giles
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or
//  without modification, are permitted provided that the
//  following conditions are met:
//
//    * Redistributions of source code must retain the above
//      copyright notice, this list of conditions and the
//      following disclaimer.
//    * Redistributions in binary form must reproduce the
//      above copyright notice, this list of conditions and
//      the following disclaimer in the documentation and/or
//      other materials provided with the distribution.
//    * Neither the name 'MAME' nor the names of its
//      contributors may be used to endorse or promote
//      products derived from this software without specific
//      prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND
//  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
//  EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
//  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
//  DAMAGE (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
//  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//============================================================

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

// MAME headers
#include "emucore.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 = global_alloc_clear(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)
		global_free(gdi->bmdata);
	global_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;
		global_free(gdi->bmdata);
		gdi->bmdata = global_alloc_array(UINT8, 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"
