/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "image/depth.hh"
#include "image/image32.hh"

#include "video/opengl/opengl_display.hh"

#include 
#include 
#include 
#include 
#include 

int glx_attriblist[] = {
  GLX_RGBA,               /* I want only TrueColor visuals */
  GLX_LEVEL, 0,           /* What is this? */
  GLX_DOUBLEBUFFER,       /* I definitely need this. */
  GLX_AUX_BUFFERS, 0,     /* What is this? */
  GLX_RED_SIZE, 8,
  GLX_GREEN_SIZE, 8,
  GLX_BLUE_SIZE, 8, 
  GLX_ALPHA_SIZE, 0,
  GLX_DEPTH_SIZE, 16,     /* I want a min 32-bit deep buffer */
  GLX_STENCIL_SIZE, 0, 

  GLX_ACCUM_RED_SIZE, 0,
  GLX_ACCUM_BLUE_SIZE, 0,
  GLX_ACCUM_GREEN_SIZE, 0,
  GLX_ACCUM_ALPHA_SIZE, 0,

  GLX_TRANSPARENT_INDEX_VALUE_EXT, 0,
  GLX_TRANSPARENT_RED_VALUE_EXT, 0,
  GLX_TRANSPARENT_GREEN_VALUE_EXT, 0,
  GLX_TRANSPARENT_BLUE_VALUE_EXT, 0, 
  GLX_TRANSPARENT_ALPHA_VALUE_EXT, 0,

  None /* end of list */
};


opengl_display_class::opengl_display_class()
{
  know_if_available=i4_F;
}

i4_bool opengl_display_class::set_mouse_shape(i4_cursor_class *cursor)
{
  if (mcursor)
    delete mcursor;

  if (cursor && cursor->pict)
    mcursor=cursor->copy();
  else 
    mcursor=0;

  return i4_T;
}



i4_bool opengl_display_class::available()
{
  if (!know_if_available)
  {
    if (input.open_display())
    {
      if (glXQueryExtension(input.display, &GLX_error_base, &GLX_event_base))
        known_availability=i4_T;          
      else
        known_availability=i4_F;
    }
    else
      known_availability=i4_F;

    know_if_available=i4_T;
    input.close_display(); 
  }

  return know_if_available;
}

void opengl_display_class::remove_cursor(sw32 x, sw32 y, i4_image_class *mouse_save)
{
  
  /*      glRasterPos2d(a->x1 *2 / (float)(width()) -1,  
                  (height()-a->y1) *2/ (float)height() -1 );

    glPixelStorei(GL_UNPACK_ROW_LENGTH, width());

    glDrawPixels(a->x2-a->x1+1, a->y2-a->y1+1, GL_RGBA, GL_UNSIGNED_BYTE, 
                 ((I4_SCREEN_TYPE *)fake_screen)->local_sub_data(a->x1, a->y1));
                 */
}

void opengl_display_class::save_and_draw_cursor(sw32 x, sw32 y, i4_image_class *&mouse_save)
{
}



XVisualInfo *opengl_display_class::get_visual(Display *display)
{
  int i,j;
  XVisualInfo dummy, *x_visinfo;
  int num_vis;
  int screen_list[16]; /* if you've got more than 16 screens, yer sick */

  x_visinfo = XGetVisualInfo(display, 0, &dummy, &num_vis);

  int num_screens = 0;
  for (i=0 ; iboth_dirty->intersect_area(0,0,width()-1,height()-1);

  i4_image_class **cur_save;

  // if this is the first time to save, or last save wave to mouse_save2 then use 1
  if (!prev_mouse_save || prev_mouse_save==mouse_save2)
    cur_save=&mouse_save1;
  else
    cur_save=&mouse_save2;
 
  save_and_draw_cursor(mouse_x - (sw32)mcursor->hot_x, mouse_y - (sw32)mcursor->hot_y, *cur_save);


  if (prev_mouse_save)
    remove_cursor(last_mouse_x, last_mouse_y, prev_mouse_save);

  prev_mouse_save=*cur_save;
  last_mouse_x=mouse_x - (sw32)mcursor->hot_x;
  last_mouse_y=mouse_y - (sw32)mcursor->hot_y;


  i4_rect_list_class::area_iter a=context->both_dirty->list.begin();
  for (;a!=context->both_dirty->list.end();++a)
    next_frame_copy.add_area(a->x1, a->y1, a->x2, a->y2);


  glDisable(GL_TEXTURE_2D);  
  glDepthFunc(GL_ALWAYS);
  glDisable(GL_BLEND);
  glColorMask(1,1,1,0);


  glViewport(0,0, width(), height());
  glPixelZoom(1,-1);

  a=next_frame_copy.list.begin();
  for (;a!=context->both_dirty->list.end();++a)
  {  
    float x,y;
    get_pl_pos(a->x1, a->y1, x,y);
    glRasterPos2d(x, y);

    glPixelStorei(GL_UNPACK_ROW_LENGTH, width());

    glDrawPixels(a->x2-a->x1+1, a->y2-a->y1+1, GL_RGBA, GL_UNSIGNED_BYTE, 
                 ((I4_SCREEN_TYPE *)fake_screen)->local_sub_data(a->x1, a->y1));
    
  }  

  glFlush();

  glXSwapBuffers(input.display, input.mainwin);


  next_frame_copy.swap(context->both_dirty);
  context->both_dirty->delete_list();

}


i4_bool opengl_display_class::close()
{
  input.close_display();
  if (fake_screen)
  {
    delete fake_screen;
    fake_screen=0;

    if (context)
    {
      delete context;
      context=0;
    }
  }
  return i4_T;
}


i4_display_class::mode *opengl_display_class::get_first_mode()
{
  if (!input.open_display())
    return 0;
  else
  {
    XVisualInfo *v = get_visual(input.display);
    if (v)
    {
      strcpy(amode.name,"Standard X11 window");
      amode.flags=mode::RESOLUTION_DETERMINED_ON_OPEN;
      amode.bits_per_pixel=I4_SCREEN_DEPTH;

      amode.red_mask    = v->red_mask<<8;
      amode.green_mask  = v->green_mask<<8;
      amode.blue_mask   = v->blue_mask<<8;
      XFree((char *)v);

      Window root;
      int x,y;
      unsigned w,h,bord,depth;
      if (XGetGeometry(input.display,
                       RootWindow(input.display,DefaultScreen(input.display)),&root, 
                       &x,&y,&w,&h,&bord,&depth)==0)
        i4_error("can't get root window attributes");

      amode.xres=w;
      amode.yres=h;

      return &amode;
    }
    return 0;
  }
}

i4_bool opengl_display_class::initialize_mode(mode *m)
{
  sw32 width=m->xres;
  sw32 height=m->yres;

  if (input.create_window(0,0,width,height, this, i4_F, get_visual(input.display)))
  {
    int GLX_major, GLX_minor;

    if (glXQueryVersion(input.display, &GLX_major, &GLX_minor))
      i4_warning("GLX v%d.%d\n", GLX_major, GLX_minor);

    i4_pixel_format f;
    f.red_mask   = m->red_mask;
    f.green_mask = m->green_mask;
    f.blue_mask  = m->blue_mask;
    f.alpha_mask=0;
    f.calc_shift();

    f.lookup      = 0;
    f.pixel_depth = I4_16BIT;

    pal = i4_pal_man.register_pal(&f);

    fake_screen=new I4_SCREEN_TYPE(width, height, pal);
    
    context=new i4_draw_context_class(0,0, width-1, height-1);
    context->both_dirty=new i4_rect_list_class;
    context->single_dirty=new i4_rect_list_class;


    return i4_T;
  }
  else 
    return i4_F;
}