#include "allegro.h"
#include "alleggl.h"

#ifdef _WIN32
#include "winalleg.h"

#include <winsock.h>
#define GFX_FULLSCREEN GFX_DIRECTX_ACCEL
#define GFX_WINDOWED GFX_DIRECTX_WIN
#else
#define SOCKET_ERROR -1
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#define GFX_FULLSCREEN GFX_AUTODETECT_FULLSCREEN
#define GFX_WINDOWED GFX_AUTODETECT_WINDOWED
#endif
#include <allegro/internal/aintern.h>


//include "fblend.h"

#include "2xsai.h"
#include "defs.h"
#include "render.h"

GLuint texture;
int texFormat;
int texType;

static void screen_blit_from_memory (struct BITMAP *source, int width, int height)
{
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	glRasterPos2i(0, 0);
	glPixelZoom ((float)screen->w / (float)width, -((float)screen->h / (float)height));
	glPixelStorei(GL_UNPACK_ROW_LENGTH, (source->line[1] - source->line[0]) / BYTES_PER_PIXEL(source->vtable->color_depth));
	glDrawPixels(width, height, allegro_gl_get_bitmap_color_format(source),
		allegro_gl_get_bitmap_type(source), (void *)source->line[0]);
}

GLuint gl_make_texture(BITMAP *bmp)
{
	GLuint tex = 0;
	
    texFormat = allegro_gl_get_bitmap_color_format(bmp);
    texType = allegro_gl_get_bitmap_type(bmp);

	allegro_gl_begin();
	
	glGenTextures(1, &tex);
	if (!tex) {
		return 0;
	}

	glBindTexture(GL_TEXTURE_2D, tex);

	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

	glTexImage2D(GL_TEXTURE_2D, 0, allegro_gl_get_texture_format(bmp),
		bmp->w, bmp->h, 0, texFormat, texType, bmp->line[0]);

	
	allegro_gl_end();
	
	return tex;
}

int initRenderer(char fullScreen)
{
   int i;
   int x, y, mode;

   if ((stretch == RENDER_GL3) && (splitScreen < 3))
      stretch = RENDER_GL;
   if ((stretch == RENDER_STRETCH2) && (splitScreen < 3))
      stretch = RENDER_STRETCH;
   
   switch (stretch)
   {
   case (RENDER_SMALL):
      if (fullScreen)
      {
         mode = GFX_FULLSCREEN;
      }
      else
      {
         mode = GFX_WINDOWED;
      }
      x = 320;
      y = 200;
      break;
   case (RENDER_SMALL2):
      if (fullScreen)
      {
         mode = GFX_FULLSCREEN;
      }
      else
      {
         mode = GFX_WINDOWED;
      }
      x = 320;
      y = 240;
      break;
   case (RENDER_STRETCH):
   case (RENDER_STRETCH2):
      if (fullScreen)
      {
         mode = GFX_FULLSCREEN;
      }
      else
      {
         mode = GFX_WINDOWED;
      }
      x = 640;
      y = 480;
      break;
   case (RENDER_2xSAI):
   case (RENDER_SUPER2xSAI):
      if (fullScreen)
      {
         mode = GFX_FULLSCREEN;
      }
      else
      {
         mode = GFX_WINDOWED;
      }
      x = 640;
      y = 480;
      tmpb = create_bitmap_ex(16, 320, 200);
      clear_bitmap(tmpb);
      tmpd = create_bitmap_ex(16, 640, 400);
      clear_bitmap(tmpd);
      break;
   case (RENDER_GL):
   case (RENDER_GL2):
   case (RENDER_GL3):
      if (install_allegro_gl())
      {
         allegro_message("Error initializing OpenGL.");
         return -1;
      };
      allegro_gl_clear_settings();
      allegro_gl_set(AGL_COLOR_DEPTH, 32);
      allegro_gl_set(AGL_RENDERMETHOD, 1);
      allegro_gl_set(AGL_DOUBLEBUFFER, TRUE);
      if (fullScreen)
      {
         allegro_gl_set(AGL_FULLSCREEN, TRUE);
         allegro_gl_set(AGL_SUGGEST, AGL_FULLSCREEN | AGL_RENDERMETHOD | AGL_COLOR_DEPTH | AGL_DOUBLEBUFFER);
      } else {
         allegro_gl_set(AGL_WINDOWED, TRUE);
         allegro_gl_set(AGL_SUGGEST, AGL_WINDOWED | AGL_RENDERMETHOD | AGL_COLOR_DEPTH | AGL_DOUBLEBUFFER);
      }
      allegro_gl_set_texture_format(GL_RGB8);
      mode = GFX_OPENGL;
      x = stretchX;
      y = stretchY;
   break;
   }

   set_color_depth(32);
   i = set_gfx_mode(mode, x, y, 0, 0);
   if (i != 0)
      return i;
   set_display_switch_mode(SWITCH_BACKGROUND);
   set_color_conversion(COLORCONV_TOTAL);

   switch (stretch)
   {
   case (RENDER_SMALL):
   case (RENDER_SMALL2):
   case (RENDER_STRETCH):
      buffer = create_system_bitmap(320, 200);
      break;
   case (RENDER_STRETCH2):
      buffer = create_system_bitmap(640, 400);
      break;
   case (RENDER_2xSAI):
   case (RENDER_SUPER2xSAI):
      buffer = create_system_bitmap(320, 200);
      break;
   case (RENDER_GL):
   case (RENDER_GL2):
   case (RENDER_GL3):
      //allegro_gl_screen_mode(AGL_MODE_DIRECT);
      glClear(GL_COLOR_BUFFER_BIT);
      glViewport(0, 0, SCREEN_W, SCREEN_H);

      glDisable(GL_DEPTH_TEST);
      glDisable(GL_CULL_FACE);
      glDisable(GL_FOG);
      glDisable(GL_LIGHTING);
      glDisable(GL_BLEND);
      glEnable(GL_TEXTURE_2D);

      allegro_gl_use_mipmapping(FALSE);	
      allegro_gl_set_projection();

      if (stretch == RENDER_GL)
         buffer = create_bitmap(512, 256);
      else
      if (stretch == RENDER_GL2)
         buffer = create_bitmap(320, 200);
      else
         buffer = create_bitmap(1024, 512);
   break;
   }
   if (buffer == NULL)
      return -1;
   return 0;
}

void freeRenderer()
{
   switch (stretch)
   {
   case (RENDER_SMALL):
      break;
   case (RENDER_SMALL2):
      break;
   case (RENDER_STRETCH):
      break;
   case (RENDER_2xSAI):
   case (RENDER_SUPER2xSAI):
      if (tmpb) destroy_bitmap(tmpb);
      if (tmpd) destroy_bitmap(tmpd);
      break;
   case (RENDER_GL):
   case (RENDER_GL3):
      if (texture)
         glDeleteTextures(1, &texture);
      break;
   }
   destroy_bitmap(buffer);
}

void render()
{
   unsigned char delta=0;
   switch (stretch)
   {
   case (RENDER_SMALL):
      blit(buffer, screen, 0, 0, 0, 0, 320, 200);
      break;
   case (RENDER_SMALL2):
      blit(buffer, screen, 0, 0, 0, 20, 320, 200);
      break;
   case (RENDER_STRETCH):
      blit(buffer, screen, 0, 0, 0, 20, 320, 200);
//      fblend_2x_stretch(buffer, screen, 0, 0, 0, 40, 320, 200);
      break;
   case (RENDER_STRETCH2):
      blit(buffer, screen, 0, 0, 0, 40, 640, 400);
      break;
   case (RENDER_2xSAI):
      blit(buffer, tmpb, 0, 0, 0, 0, 320, 200);
      _2xSaI((unsigned char *)tmpb->dat, tmpb->w*2, &delta, tmpd, buffer->w, buffer->h);
      blit(tmpd, screen, 0, 0, 0, 40, 640, 399);
      break;
   case (RENDER_SUPER2xSAI):
      blit(buffer, tmpb, 0, 0, 0, 0, 320, 200);
      Super2xSaI((unsigned char *)tmpb->dat, tmpb->w*2, &delta, tmpd, buffer->w, buffer->h);
      blit(tmpd, screen, 0, 0, 0, 40, 640, 399);
      break;
   case (RENDER_GL):
   case (RENDER_GL3):
      if (texture)
      {
         glBindTexture(GL_TEXTURE_2D, texture);
         glTexImage2D(GL_TEXTURE_2D, 0, allegro_gl_get_texture_format(buffer),
          buffer->w, buffer->h, 0, texFormat, texType, buffer->line[0]);
      } else {
         texture = gl_make_texture(buffer);
         glBindTexture(GL_TEXTURE_2D, texture);
      }
      glBegin(GL_QUADS);
      glTexCoord2f(0.0f, 0.78125f); glVertex3f(0.0f, (float)SCREEN_H,  0.0f);	// Bottom Left Of The Texture and Quad
		glTexCoord2f(0.625f, 0.78125f); glVertex3f( (float)SCREEN_W, (float)SCREEN_H,  0.0f);	// Bottom Right Of The Texture and Quad
		glTexCoord2f(0.625f, 0.0f); glVertex3f( (float)SCREEN_W,  0.0f,  0.0f);	// Top Right Of The Texture and Quad
		glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f,  0.0f,  0.0f);         
      glEnd();
      allegro_gl_flip();
      break;
   case (RENDER_GL2):
      screen_blit_from_memory(buffer, 320, 200);
      allegro_gl_flip();
      break;
   }
}
