/***************************************************************************

  SDLgfx.cpp

  Gambas extension using SDL

  (c) 2006 Laurent Carlier <lordheavy@users.sourceforge.net>
           Benoît Minisini <gambas@users.sourceforge.net>

  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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.

***************************************************************************/

#include "SDLgfx.h"
#include "SDLcore.h"
#include "SDLapp.h"

#include <iostream>
#include <math.h>

// texture status values
#define TEXTURE_OK		(0)
#define TEXTURE_TO_RELOAD	(1<<0)
#define TEX_TO_REDEFINE 	(1<<1)

// for ellipses
#define PI 3.14159265359

// debug
// #define DEBUGGFX

// fill patterns
static GLubyte VertPattern[] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};

static GLubyte HoriPattern[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,	
				0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,	
				0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00, 
				0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,	
				0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,	
				0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00, 
				0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,	
				0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00};

static GLubyte CrosPattern[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 
				0x22, 0x22, 0x22, 0x22, 0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xFF, 0xFF, 0xFF, 0xFF,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xFF, 0xFF, 0xFF, 0xFF,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
				0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,	
 				0x22, 0x22, 0x22, 0x22, 0xFF, 0xFF, 0xFF, 0xFF, 0x22, 0x22, 0x22, 0x22,	
				0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};

static GLubyte BdiaPattern[] = {0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 
				0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 
				0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x80, 0x80, 0x80, 0x80, 
				0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 
				0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 
				0x01, 0x01, 0x01, 0x01, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 
				0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 
				0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 
				0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 
				0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 
				0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01};

static GLubyte DiaPattern[] =  {0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 
				0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 
				0x40, 0x40, 0x40, 0x40, 0x80, 0x80, 0x80, 0x80, 0x01, 0x01, 0x01, 0x01, 
				0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 
				0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 
				0x80, 0x80, 0x80, 0x80, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 
				0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 
				0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x40, 0x80, 0x80, 0x80, 0x80, 
				0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 
				0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 
				0x40, 0x40, 0x40, 0x40, 0x80, 0x80, 0x80, 0x80};

static GLubyte DiaCPattern[] = {0x81, 0x81, 0x81, 0x81, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x24, 
				0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24, 0x24, 
				0x42, 0x42, 0x42, 0x42, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 
				0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x24, 0x18, 0x18, 0x18, 0x18, 
				0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 
				0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x42, 0x42, 0x42, 0x42, 
				0x24, 0x24, 0x24, 0x24, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
				0x24, 0x24, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x81, 0x81, 0x81, 0x81, 
				0x81, 0x81, 0x81, 0x81, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x24, 0x24, 
				0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24, 0x24, 
				0x42, 0x42, 0x42, 0x42, 0x81, 0x81, 0x81, 0x81};

static GLubyte Dns1Pattern[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

static GLubyte Dns2Pattern[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0x77, 0x77, 0x77, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 
				0x77, 0x77, 0x77, 0x77, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 
				0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0x77, 0x77, 0x77, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0x77, 0x77, 0x77, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 
				0x77, 0x77, 0x77, 0x77, 0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 
				0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0x77, 0x77, 0x77, 0xFF, 0xFF, 0xFF, 0xFF, 
				0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0x77, 0x77, 0x77, 
				0xFF, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD, 0xDD, 0xDD, 0xFF, 0xFF, 0xFF, 0xFF, 
				0x77, 0x77, 0x77, 0x77, 0xFF, 0xFF, 0xFF, 0xFF};

static GLubyte Dns3Pattern[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xAA, 0xAA, 0xAA, 0xAA, 0x77, 0x77, 0x77, 0x77, 
				0xAA, 0xAA, 0xAA, 0xAA, 0xDD, 0xDD, 0xDD, 0xDD, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x77, 0x77, 0x77, 0x77, 0xAA, 0xAA, 0xAA, 0xAA, 0xDD, 0xDD, 0xDD, 0xDD, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x77, 0x77, 0x77, 0x77, 0xAA, 0xAA, 0xAA, 0xAA, 
				0xDD, 0xDD, 0xDD, 0xDD, 0xAA, 0xAA, 0xAA, 0xAA, 0x77, 0x77, 0x77, 0x77, 
				0xAA, 0xAA, 0xAA, 0xAA, 0xDD, 0xDD, 0xDD, 0xDD, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x77, 0x77, 0x77, 0x77, 0xAA, 0xAA, 0xAA, 0xAA, 0xDD, 0xDD, 0xDD, 0xDD, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x77, 0x77, 0x77, 0x77, 0xAA, 0xAA, 0xAA, 0xAA, 
				0xDD, 0xDD, 0xDD, 0xDD, 0xAA, 0xAA, 0xAA, 0xAA, 0x77, 0x77, 0x77, 0x77, 
				0xAA, 0xAA, 0xAA, 0xAA, 0xDD, 0xDD, 0xDD, 0xDD, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x77, 0x77, 0x77, 0x77, 0xAA, 0xAA, 0xAA, 0xAA};

static GLubyte Dns4Pattern[] = {0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA};

static GLubyte Dns5Pattern[] = {0xAA, 0xAA, 0xAA, 0xAA, 0x44, 0x44, 0x44, 0x44, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x11, 0x11, 0x11, 0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0x44, 0x44, 0x44, 0x44, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x11, 0x11, 0x11, 0x11, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x44, 0x44, 0x44, 0x44, 0xAA, 0xAA, 0xAA, 0xAA, 0x11, 0x11, 0x11, 0x11, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x44, 0x44, 0x44, 0x44, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x11, 0x11, 0x11, 0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0x44, 0x44, 0x44, 0x44, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x11, 0x11, 0x11, 0x11, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x44, 0x44, 0x44, 0x44, 0xAA, 0xAA, 0xAA, 0xAA, 0x11, 0x11, 0x11, 0x11, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x44, 0x44, 0x44, 0x44, 0xAA, 0xAA, 0xAA, 0xAA, 
				0x11, 0x11, 0x11, 0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0x44, 0x44, 0x44, 0x44, 
				0xAA, 0xAA, 0xAA, 0xAA, 0x11, 0x11, 0x11, 0x11};

static GLubyte Dns6Pattern[] = {0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 
				0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 
				0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 
				0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 
				0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 
				0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 
				0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 
				0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 
				0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 
				0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 
				0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00};

static GLubyte Dns7Pattern[] = {0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 
				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

static void SetLinePattern(int value)
{
	GLushort pattern = 0xFFFF;

	if (value == SDL::SolidLine)
		return;
	if (value == SDL::DotLine)
		pattern = 0xCCCC;
	if (value == SDL::DashLine)
		pattern = 0xAAAA;
	if (value == SDL::DashDotLine)
		pattern = 0xE4E4;
	if (value == SDL::DashDotDotLine)
		pattern = 0xF98C;

	glEnable(GL_LINE_STIPPLE);
	glLineStipple(2, pattern);
}

static void SetFillPattern(int value)
{
	if (!value)
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	else
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	if (value <= SDL::SolidFill)
		return;

	glEnable(GL_POLYGON_STIPPLE);

	if (value == SDL::VerticalFill)
		glPolygonStipple(VertPattern);

	if (value == SDL::HorizontalFill)
		glPolygonStipple(HoriPattern);

	if (value == SDL::CrossFill)
		glPolygonStipple(CrosPattern);

	if (value == SDL::BackDiagFill)
		glPolygonStipple(BdiaPattern);

	if (value == SDL::DiagFill)
		glPolygonStipple(DiaPattern);

	if (value == SDL::DiagCrossFill)
		glPolygonStipple(DiaCPattern);

	if (value == SDL::Dense1Fill)
		glPolygonStipple(Dns1Pattern);

	if (value == SDL::Dense2Fill)
		glPolygonStipple(Dns2Pattern);

	if (value == SDL::Dense3Fill)
		glPolygonStipple(Dns3Pattern);

	if (value == SDL::Dense4Fill)
		glPolygonStipple(Dns4Pattern);

	if (value == SDL::Dense5Fill)
		glPolygonStipple(Dns5Pattern);

	if (value == SDL::Dense6Fill)
		glPolygonStipple(Dns6Pattern);

	if (value == SDL::Dense7Fill)
		glPolygonStipple(Dns7Pattern);
}

SDLgfx::SDLgfx(SDLwindow *window)
{
	hSurfaceInfo = window->hSurfaceInfo;
	hWindowDraw = true;
	hContextDefined = false;
	resetGfx();
}

SDLgfx::SDLgfx(SDLsurface *surface)
{
	hSurfaceInfo = surface->hSurfaceInfo;
	hWindowDraw = false;
	hContextDefined = false;
	resetGfx();

	/* Does the surface already got a context (a Pbuffer is already defined ?) */
	if (hContext)
		return;

	/* we define the pixel buffer if needed */
	int scrnum;
	GLXFBConfig *fbconfig;
	XVisualInfo *visinfo;
	int nitems;
	Display *disp = SDLapp->X11appDisplay();

	int attrib[] = 
	{
		GLX_DOUBLEBUFFER,  False,
		GLX_RED_SIZE,      1,
		GLX_GREEN_SIZE,    1,
		GLX_BLUE_SIZE,     1,
		GLX_RENDER_TYPE,   GLX_RGBA_BIT,
		GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
		None
	};

	int pbufAttrib[] = 
	{
		GLX_PBUFFER_WIDTH,   hSurface->w,
		GLX_PBUFFER_HEIGHT,  hSurface->h,
		GLX_LARGEST_PBUFFER, False,
		None
	};

	SDLapp->LockX11();

	scrnum = DefaultScreen(disp);
	fbconfig = glXChooseFBConfig(disp, scrnum, attrib, &nitems);

	if (!fbconfig)
	{
        	SDLcore::RaiseError("SDLgfx: error, couldn't get fbconfig");
        	return;
	}

	hPbuffer = glXCreatePbuffer(disp, fbconfig[0], pbufAttrib);
	visinfo = glXGetVisualFromFBConfig(disp, fbconfig[0] );

	if (!visinfo )
	{
        	SDLcore::RaiseError("SDLgfx: error, couldn't get an RGBA, double-buffered visual");
		return;
	}

	if (!SDLcore::GetWindow())
	{
        	SDLcore::RaiseError("SDLgfx: window not defined, will be fixed later !");
		return;
	}

	hContext = glXCreateContext(disp, visinfo, SDLcore::GetWindow()->hSurfaceInfo->Ctx, GL_TRUE);

	if (!hContext )
	{
		SDLcore::RaiseError("SDLgfx: error, Call to glXCreateContext failed!");
		return;
	}

	XFree(fbconfig);
	XFree(visinfo);
	hContextDefined = true;

	SDLapp->UnlockX11();
}

SDLgfx::~SDLgfx()
{
	if (hWindowDraw)
		return;

	if (!hContextDefined)
		return;

	Display *disp = SDLapp->X11appDisplay();
	glXDestroyContext(disp, hContext);
	glXDestroyPbuffer(disp, hPbuffer);
}

void SDLgfx::resetGfx(void)
{
	hForeColor = 0xFFFFFFFF;
	hBackColor = 0x00000000;
	hLine = SDL::SolidLine;
	hLineWidth = 1;
	hFill = SDL::NoFill;
	hTextureStatus = TEXTURE_TO_RELOAD;
}

void SDLgfx::SetLineStyle(int style)
{
	if (style>SDL::DashDotDotLine)
		style = SDL::DashDotDotLine;

	hLine = style;
}

void SDLgfx::SetFillStyle(int style)
{
	if (style>SDL::Dense7Fill)
		style = SDL::Dense7Fill;

	hFill = style;
}

void SDLgfx::Clear(void)
{
	if (!hSurface)
		return;

	Uint32 myColor = hBackColor;

	if (hSurface->flags & SDL_OPENGL)
	{
		glClearColor((GLfloat((hBackColor >> 24) & 0xFF)/255), (GLfloat((hBackColor >> 16) & 0xFF)/255), (GLfloat((hBackColor >> 8) & 0xFF)/255), 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
	}
	else
	{
		Uint32 FillColor = SDL_MapRGB(hSurface->format, ((hBackColor >> 24) & 0xFF), ((hBackColor >> 16) & 0xFF), ((hBackColor >> 8) & 0xFF));

		if (SDL_FillRect(hSurface, NULL, FillColor)<0)
			SDLcore::RaiseError(SDL_GetError());
	}

	hBackColor = myColor;
	hTextureStatus = TEXTURE_TO_RELOAD;
}

void SDLgfx::DrawPixel(int x, int y)
{
	if (!hSurface)
		return;

	glBegin(GL_POINTS);
	glColor4f((GLfloat((hForeColor >> 24) & 0xFF)/ 255), (GLfloat((hForeColor >> 16) & 0xFF)/255), (GLfloat((hForeColor >> 8) & 0xFF)/255), (GLfloat(hForeColor  & 0xFF)/255));
	glVertex2i(x, y);
	glEnd();

	hTextureStatus = TEXTURE_TO_RELOAD;
}

void SDLgfx::DrawLine(int x1, int y1, int x2, int y2)
{
	if (!hSurface)
		return;

	if (!hLine) // SDLgfx::NoLine
		return;

	if (hSurface->flags & SDL_OPENGL)
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		SetLinePattern(hLine);
		glLineWidth(GLfloat(hLineWidth));

		glBegin(GL_LINES);
		glColor4f((GLfloat((hForeColor >> 24) & 0xFF)/ 255), (GLfloat((hForeColor >> 16) & 0xFF)/255), (GLfloat((hForeColor >> 8) & 0xFF)/255), (GLfloat(hForeColor  & 0xFF)/255));
		glVertex2i(x1, y1);
		glVertex2i(x2, y2);
		glEnd();

		glPopAttrib();
	}

	hTextureStatus = TEXTURE_TO_RELOAD;
}

void SDLgfx::DrawRect(int x, int y, int w, int h)
{
	if (!hSurface)
		return;

	if (!hFill && !hLine)
		return;

	if (hSurface->flags & SDL_OPENGL)
	{
		glPushAttrib(GL_ALL_ATTRIB_BITS);

		SetFillPattern(hFill);

		glColor4f((GLfloat((hForeColor >> 24) & 0xFF)/ 255), (GLfloat((hForeColor >> 16) & 0xFF)/255), (GLfloat((hForeColor >> 8) & 0xFF)/255), (GLfloat(hForeColor  & 0xFF)/255));
		glBegin(GL_QUADS);
		glVertex2i(x, y);
		glVertex2i(x+w, y);
		glVertex2i(x+w, y+h);
		glVertex2i(x, y+h);
		glEnd();

		if (hFill>SDL::SolidFill)
		{
			SetFillPattern(SDL::NoFill);
			SetLinePattern(hLine);
			glLineWidth(GLfloat(hLineWidth));

			glBegin(GL_QUADS);
			glVertex2i(x, y);
			glVertex2i(x+w, y);
			glVertex2i(x+w, y+h);
			glVertex2i(x, y+h);
			glEnd();
		}

		glPopAttrib();
	}
}

void SDLgfx::DrawEllipse(int x, int y, int w, int h)
{
	if (!hSurface)
		return;

	if (!hFill && !hLine)
		return;

	double angle;
	double step = 2 * PI / 360;

	glPushAttrib(GL_ALL_ATTRIB_BITS);

	SetFillPattern(hFill);

	glColor4f((GLfloat((hForeColor >> 24) & 0xFF)/ 255), (GLfloat((hForeColor >> 16) & 0xFF)/255), (GLfloat((hForeColor >> 8) & 0xFF)/255), (GLfloat(hForeColor  & 0xFF)/255));

	glBegin(GL_POLYGON);

	for (angle=0; angle < 2 * PI; angle += step)
	{
		glVertex2d(x + (w * cos(angle)), y + (h * sin(angle)));
	}
	glEnd();

	if (hFill>SDL::SolidFill)
	{
		SetFillPattern(SDL::NoFill);
		SetLinePattern(hLine);
		glLineWidth(GLfloat(hLineWidth));

		glBegin(GL_POLYGON);
		for (angle=0; angle < 2 * PI; angle += step)
		{
			glVertex2d(x + (w * cos(angle)), y + (h * sin(angle)));
		}
		glEnd();
	}

	glPopAttrib();
}

void SDLgfx::Blit(SDLsurface *surface, int x, int y, int srcX, int srcY,
		 int srcWidth, int srcHeight, int width, int height)
{
	if (!hSurface)
		return;

	// will keep current SDL_INFO struct
	SDL_INFO *tmpInfo = hSurfaceInfo;
	int myWidth = 0, myHeight = 0;

	// we will work with the SDLsurface SDL_INFO struct
	hSurfaceInfo = surface->hSurfaceInfo;

	if (!hSurface)
		goto _endblit;

	if ((srcX > hSurface->w) || (srcY > hSurface->h))
		goto _endblit;

	if ((srcHeight<0) || ((srcY + srcHeight) > hSurface->h))
		myHeight = hSurface->h - srcY;
	else
		myHeight = srcHeight;

	if ((srcWidth<0) || ((srcX + srcWidth) > hSurface->w))
		myWidth = hSurface->w - srcX;
	else
		myWidth = srcWidth;

	GLdouble myTexX, myTexY, myTexHeight, myTexWidth;
	ManageTexture();

	myTexX = ((srcX * hTextureWidth) / hSurface->w);
	myTexY = ((srcY * hTextureHeight) / hSurface->h);
	myTexWidth = (((srcX + myWidth)* hTextureWidth) / hSurface->w);
	myTexHeight = (((srcY + myHeight)* hTextureHeight) / hSurface->h);

	if (width != -1)
		myWidth = width;

	if (height != -1)
		myHeight = height;

	glBegin(GL_QUADS);
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glTexCoord2d(myTexX, myTexY);
	glVertex2i(x, y);

	glTexCoord2d(myTexX, myTexHeight);
	glVertex2i(x, y + myHeight);

	glTexCoord2d(myTexWidth, myTexHeight);
	glVertex2i(x + myWidth, y + myHeight);

	glTexCoord2d(myTexWidth, myTexY);
	glVertex2i(x + myWidth, y);
	glEnd();

_endblit:
	hSurfaceInfo = tmpInfo;
}

static int power_of_two(int input)
{
	int value = 1;

	while ( value < input )
	{
		value <<= 1;
	}
	return value;
}

void SDLgfx::ManageTexture()
{
	if (!hTexture)
	{
		glGenTextures(1, &hTexture);
		hTextureStatus = TEXTURE_TO_RELOAD;
	}

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, hTexture);

	if (hTextureStatus & TEXTURE_TO_RELOAD)
	{
		#ifdef DEBUGGFX
		std::cout << "Loading texture " << hTextureIndex << std::endl;
		#endif

		int w, h;
		SDL_Surface *image;
		Uint32 saved_flags;
		Uint8  saved_alpha;

		/* Use the surface width and height expanded to powers of 2 */
		w = power_of_two(hSurface->w);
		h = power_of_two(hSurface->h);
		hTextureWidth = GLdouble(hSurface->w) / w;  /* Max X */
		hTextureHeight = GLdouble(hSurface->h) / h;  /* Max Y */

		image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
			0x000000FF, 
			0x0000FF00, 
			0x00FF0000, 
			0xFF000000
#else
			0xFF000000,
			0x00FF0000, 
			0x0000FF00, 
			0x000000FF
#endif
			);

		if ( image == NULL )
			return;

		/* Save the alpha blending attributes */
		saved_flags = hSurface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
		saved_alpha = hSurface->format->alpha;

		if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
			SDL_SetAlpha(hSurface, 0, 0);

		/* Copy the surface into the GL texture image */
		SDL_BlitSurface(hSurface, NULL, image, NULL);

		/* Restore the alpha blending attributes */
		if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA )
			SDL_SetAlpha(hSurface, saved_flags, saved_alpha);

		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, 
			GL_UNSIGNED_BYTE, image->pixels);
		/* Use of CLAMP_TO_EDGE, without it give a black line around the texture
		with DRI radeon drivers */
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		SDL_FreeSurface(image); /* No longer needed */

		hTextureStatus = TEXTURE_OK;
	}
}	
