/*
 * PVVMUD a 3D MUD
 * Copyright (C) 1998-1999  Programvareverkstedet (pvv@pvv.org)
 *
 * 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 <iostream.h>
#include "pvvmud.H"
#include "glrenderer.H"
#include "cliviewpoint.H"
#include "pvvmudclient.H"

COGLRenderer::COGLRenderer(CPvvmudClient * cli) : CRenderer(cli) {
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);

  glEnable(GL_LIGHTING);
  {
      GLfloat gray[4] = {0.2, 0.2, 0.2, 1.0};
      GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
      GLfloat ambient[4] = {0.4, 0.4, 0.4, 1.0};
      glLightfv(GL_LIGHT0, GL_AMBIENT, gray);
      glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
      glEnable(GL_LIGHT0);

      glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient);
  }
  glEnable( GL_TEXTURE_2D );
  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); 
  //  glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST );
  glDisable(GL_TEXTURE_2D);
}

COGLRenderer::~COGLRenderer(){
}

void COGLRenderer::prepareDraw(CWorldObject * object) {
  if (m_mode == GL_SELECT) {
    glLoadName(object->getObjectId());
  }
}

void COGLRenderer::draw() {
  GLfloat light_position[4] = { 0.0, 0.5, 1.0, 0.0 };

  glLoadIdentity();
  glEnable(GL_DEPTH_TEST);
//  glEnable(GL_TEXTURE_2D);
  glEnable(GL_LIGHTING);
  glClearColor(0.5,0.5,0.9,1.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix();

  glRotatef(-90, 1.0, 0.0, 0.0);
  CCliViewpoint * viewpoint = getClient()->getManager()->getViewpoint();
  viewpoint->transform();


  glLightfv(GL_LIGHT0,GL_POSITION,light_position); 

  getClient()->getManager()->animate();
  getClient()->getManager()->draw(this);

  glPopMatrix();
  if (getConsole()->isVisible()) {
    getConsole()->drawText();
  }
  glFlush();

// Moved to pvvmudclient->pollConsole()
//  const char * s = getConsole()->getLine();
//  if (s != NULL) {
//    getClient()->getManager()->sendMsg(s);
//  }

  getClient()->getGUI()->reshape(getClient()->getGUI()->getWidth(), getClient()->getGUI()->getHeight());

}

void COGLRenderer::transform(CPosition &pos, CDirection &dir) {
  const double * position = pos.getVector();
  const double * direction = dir.getVector();

  glPushMatrix();

  glTranslated(position[0],position[1],position[2]);
  glRotated(direction[2],1,0,0);
  glRotated(direction[1],0,1,0);
  glRotated(direction[0],0,0,1);
}

void COGLRenderer::reshape(int width, int height) {
  getClient()->getGUI()->setWidth(width);
  getClient()->getGUI()->setHeight(height);
  GLfloat aspectViewport = (GLfloat) height / (GLfloat) width;
  setAspectViewport(aspectViewport);
  glViewport(0, 0, (GLint) width, (GLint) height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-0.1, 0.1, -0.1*aspectViewport, 0.1*aspectViewport, 0.2, 1000.0);
  glMatrixMode(GL_MODELVIEW);
}

void COGLRenderer::postDraw() {
  glPopMatrix();
}

#define SELECTBUFSIZE 1024

void COGLRenderer::mousePick(int x, int y) {
  cdebug << "Mouse pick " << x << " " << y << "\n";

  GLuint selectBuf[SELECTBUFSIZE];
  GLint hits;
  GLint viewport[4];

  glGetIntegerv(GL_VIEWPORT, viewport);

  glSelectBuffer(SELECTBUFSIZE, selectBuf);
  glRenderMode(GL_SELECT);

  glInitNames();
  glPushName((GLuint)(-1));

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
  gluPickMatrix(x,viewport[3]-y,1.0,1.0,viewport);
  glFrustum(-0.1, 0.1, -0.1*m_aspectViewport, 0.1*m_aspectViewport, 0.2, 1000.0);
  setMode(GL_SELECT);
  draw();
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glFlush();

  hits = glRenderMode(GL_RENDER);
  getClient()->getInputFunction()->processHits(hits, selectBuf);
}
  
GLfloat COGLRenderer::getAspectViewport() {
  return m_aspectViewport;
}

void COGLRenderer::setAspectViewport(GLfloat av) {
  m_aspectViewport = av;
}

void COGLRenderer::setMode(GLenum mode) {
  m_mode = mode;
}

void COGLRenderer::dumpScreen(char * texFileName){
  GLint viewport[4];
  int width,height;
  
  BYTE *data;
  CTexture * texture = new CTexture();

  glGetIntegerv(GL_VIEWPORT,viewport);

  width = viewport[2];
  height = viewport[3];
 
  data = (BYTE*)malloc(width*height*4*sizeof(BYTE));

  glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,(GLvoid*)data);

  texture->setTextureMap(new CTextureMap(width,height,data));
  texture->save(texFileName);
  delete texture;
}