/***************************************************************************
 *            gtk_gfx.c
 *
 *  Copyright  2010  Steffen Pohle
 *  steffen@gulpe.de
 ****************************************************************************/

/*
 *  This program 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.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */


#include "map.h"
#include "gtk_port.h"
#include "memoryleak.h"
#include "system.h"

iPoint gfx_screensize;
struct image *gfx_doublebuffer = NULL;

/************************************************************************
 * functions for starting and finishing the drawing process
 */
void gfx_flip () {
	gc = gdk_gc_new (map_da->window);
	gdk_gc_get_values (gc, &gcvalues);
	gdk_draw_drawable (map_da->window, gc, gfx_doublebuffer->pixmap, 0, 0, 0, 0, gfx_screensize.x, gfx_screensize.y);
	gdk_gc_unref (gc);
};


void gfx_resize (int width, int height) {
	if (width != gfx_screensize.x || height != gfx_screensize.y) {
		if (height == 0) height = 1;
		if (width == 0) width = 1;

		gfx_screensize.x = width;
		gfx_screensize.y = height;
		if (gfx_doublebuffer) gfx_img_free (gfx_doublebuffer);
		gfx_doublebuffer = gfx_img_alloc (width, height);
	}
};


int gfx_color_alloc (struct color *c, unsigned short int r, unsigned short int g, unsigned short int b) {
	c->r = r;
	c->b = b;
	c->g = g;

	if (c->alloc && colormap != NULL) {
		gdk_colormap_free_colors (colormap, &c->c, 1);
		c->alloc = 0;
	}
	
	if (colormap != NULL) {
		c->alloc = 1;
		c->c.red = r;
		c->c.blue = b;
		c->c.green = g;
		gdk_colormap_alloc_color (colormap, &c->c, TRUE, TRUE);
	}
	else c->alloc = 0;

	return 1;
};


/***************************************************************************
 * img functions
 */
struct image *gfx_img_alloc (int w, int h) {
	struct image *img = (struct image*) ml_malloc (sizeof (struct image));
	d_printf ("img_gfx_alloc: %d,%d", w, h);
	
	img->pixmap = gdk_pixmap_new (map_da->window, w, h, -1);
	img->gc = gdk_gc_new (img->pixmap);
	img->width = w;
	img->height = h;

	return img;
};


void gfx_img_free (struct image *img) {
	gdk_gc_unref (img->gc);
	g_object_unref (img->pixmap);
	ml_free (img);
};


void gfx_clear (struct image *img, struct color *c) {
	if (img == NULL) img = gfx_doublebuffer;
	gdk_gc_set_foreground (img->gc,&c->c);
	gdk_draw_rectangle (img->pixmap, img->gc, TRUE, 0, 0, img->width, img->height);
};


void gfx_draw_img (struct image *dimg, int dx, int dy, int dw, int dh, struct image *simg, int sx, int sy) {
	if (dimg == NULL) dimg = gfx_doublebuffer;
	if (simg == NULL || simg->pixmap == NULL || dimg == NULL || dimg->pixmap == NULL) {
		d_printf ("WARN: gfx_img_draw_img drawing on NULL or from NULL image");
		d_print_backtrace ();
		return;
	}

	/* check for boundrys, do clipping */
	if (sx + dw > simg->width) dw = simg->width - sx;
	if (dx + dw > dimg->width) dw = dimg->width - dx;
	if (sy + dh > simg->height) dh = simg->height - sy;
	if (dh + dh > gfx_screensize.y) dh = dimg->height - dy;
	if (dw <= 0 || dh <= 0) return;

	/* draw the pixmap onto the screen */
	gdk_draw_drawable (dimg->pixmap, dimg->gc, simg->pixmap, sx, sy, dx, dy, dw, dh);
};


void gfx_draw_line (struct image *dimg, int x1, int y1, int x2, int y2, struct line_style style) {
	if (dimg == NULL) dimg = gfx_doublebuffer;
	gdk_gc_set_foreground (dimg->gc,&style.c.c);
	gdk_gc_set_line_attributes (dimg->gc, style.width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
	gdk_draw_line(dimg->pixmap, dimg->gc, x1, y1, x2, y2);
};


void gfx_draw_text (struct image *dimg, int x, int y, char *text, struct color *c) {
	if (dimg == NULL) dimg = gfx_doublebuffer;
	PangoLayout *layout = gtk_widget_create_pango_layout(map_da, NULL);
	pango_layout_set_text(layout, text, -1);

	gdk_gc_set_foreground (dimg->gc, &color[COLOR_white][2].c);
	gdk_draw_layout(dimg->pixmap, dimg->gc, x-1, y-1, layout);
	gdk_draw_layout(dimg->pixmap, dimg->gc, x-1, y+1, layout);
	gdk_draw_layout(dimg->pixmap, dimg->gc, x+1, y-1, layout);
	gdk_draw_layout(dimg->pixmap, dimg->gc, x+1, y+1, layout);
	
	gdk_gc_set_foreground (dimg->gc, &c->c);
	gdk_draw_layout(dimg->pixmap, dimg->gc, x, y, layout);
	g_object_unref(layout);
};


void gfx_draw_polygon (struct image *dimg, iPoint *p, int pcnt, struct line_style style, struct color *c) {
	static GdkPoint *polygon = NULL;
	static int polygon_cnt = 0;
	int i;

	if (dimg == NULL) dimg = gfx_doublebuffer;
	if (polygon_cnt < pcnt) {
		polygon_cnt = pcnt;
		if (polygon != NULL)
			polygon = (GdkPoint *) ml_realloc (polygon, sizeof (GdkPoint) * polygon_cnt);
		else
			polygon = (GdkPoint *) ml_malloc (sizeof (GdkPoint) * polygon_cnt);
	}

	for (i = 0; i < pcnt; i++) {
		polygon[i].x = p[i].x;
		polygon[i].y = p[i].y;
	}

	gdk_gc_set_foreground (dimg->gc, &c->c);
	gdk_draw_polygon (dimg->pixmap, dimg->gc, TRUE, polygon, pcnt);
};


void gfx_draw_rect (struct image *dimg, int x1, int y1, int x2, int y2, struct color *c) {
	if (dimg == NULL) dimg = gfx_doublebuffer;
	gdk_gc_set_foreground (dimg->gc, &c->c);
    gdk_draw_rectangle (dimg->pixmap, dimg->gc, TRUE, x1, y1, x2-x1, y2-y1);
};

