/* XRACER (C) 1999-2000 Richard W.M. Jones <rich@annexia.org> and other AUTHORS
 *
 * 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.
 *
 * $Id: video.c,v 1.1 2000/02/05 11:23:41 rich Exp $
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>

#include <GL/glu.h>

#include "mpeg/mpeg2.h"		/* Interface to MPEG-2 decoder library. */

#include "xracer.h"
#include "xracer-video.h"
#include "xracer-log.h"

/* Find the next value up from n which is a power of 2.
 */
static int
roundup2(int n)
{
  int m;

  for(m = 1; m < n-1 ; m *= 2)
    ;

  return m;
} 

static void *mpeg, *buffer;
static int real_width, real_height;
static int scaled_width, scaled_height;
static int xoffset, yoffset;
static int maxsize, tex;

/* Program-level initializations. */
void
xrVideoInit ()
{
  glGetIntegerv (GL_MAX_TEXTURE_SIZE, &maxsize);
  glGenTextures (1, &tex);
}

/* Load a file ready for decoding it. */
int
xrVideoLoadFile (const char *filename)
{
#ifndef DISABLE_VIDEO

  int pow2, size;

  mpeg = mpeg2OpenFile (filename);

  if (mpeg == 0)
    {
      xrLogPerror ("open: %s", filename);
      return -1;
    }

  /* Prepare a buffer for this file. Because of the limitations of
   * textures, we are going to scale the image to fit into a texture.
   */
  real_width = mpeg2GetWidth (mpeg);
  real_height = mpeg2GetHeight (mpeg);

  if (real_height > real_width)
    {
      xrLog (LOG_ERROR,
	     "%s: cannot cope with MPEG %dx%d (height > width)",
	     filename, real_width, real_height);
      mpeg2CloseFile (mpeg);
      return -1;
    }

  pow2 = roundup2 (real_width);

  if (pow2 < maxsize)
    {
      mpeg2ScaleWidthUp (mpeg, maxsize / pow2);
      mpeg2ScaleHeightUp (mpeg, maxsize / pow2);
    }
  else if (pow2 > maxsize)
    {
      mpeg2ScaleWidthDown (mpeg, pow2 / maxsize);
      mpeg2ScaleHeightDown (mpeg, pow2 / maxsize);
    }

  scaled_width = real_width * maxsize / pow2;
  scaled_height = real_height * maxsize / pow2;

  xrLog (LOG_DEBUG,
	 "%s: %dx%d scaled to %dx%d",
	 filename, real_width, real_height, scaled_width, scaled_height);

  xoffset = (maxsize - scaled_width) / 2;
  yoffset = maxsize - scaled_height; /* Assume 4:3 aspect ratio. */

  xrLog (LOG_DEBUG,
	 "%s: offset: %dx%d",
	 filename, xoffset, yoffset);

  buffer = xmalloc (size = maxsize * maxsize * 3 * sizeof (GLubyte));
  memset (buffer, 0, size);

  mpeg2SetOutputFormat (mpeg, MPEG2_OUTPUT_FORMAT_RGB);
  mpeg2SetOutputBuffer (mpeg, buffer);

  /* Create the texture object. */
  glBindTexture (GL_TEXTURE_2D, tex);

  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

  /* glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); */
  glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  glTexImage2D (GL_TEXTURE_2D,
		0,
		GL_RGB,
		maxsize, maxsize,
		0,
		GL_RGB,
		GL_UNSIGNED_BYTE,
		buffer);
  return 0;

#else /* DISABLE_VIDEO is set */
  return -1;
#endif
}

/* Unload a file from memory. */
void
xrVideoUnloadFile ()
{
#ifndef DISABLE_VIDEO
  if (mpeg) mpeg2CloseFile (mpeg);
  mpeg = 0;
#endif
}

/* Display the next frame in sequence. */
int
xrVideoDisplayNextFrame ()
{
#ifndef DISABLE_VIDEO

  int r;

  /* This causes the library to put the next frame into buffer. */
  r = mpeg2ReadNextFrame (mpeg);

  if (r <= 0)
    return r;

  glEnable (GL_TEXTURE_2D);
  glBindTexture (GL_TEXTURE_2D, tex);

  /* Replace the old texture with the new one. */
  glTexSubImage2D (GL_TEXTURE_2D,
		   0,
		   xoffset, yoffset,
		   scaled_width, scaled_height,
		   GL_RGB,
		   GL_UNSIGNED_BYTE,
		   buffer);

  /* Switch to orthographic projection. */
  glMatrixMode (GL_PROJECTION);
  glPushMatrix ();
  glLoadIdentity ();
  /*gluOrtho2D (0, (GLdouble) width, 0, (GLdouble) height);*/
  glOrtho (0, (GLdouble) xrWidth, 0, (GLdouble) xrHeight, 0, 1000);
  glMatrixMode (GL_MODELVIEW);
  glPushMatrix ();
  glLoadIdentity ();

  /* Draw a quad which fills the screen. */
  glBegin (GL_QUADS);
  glTexCoord2f (0, 1);
  glVertex2i (0, 0);
  glTexCoord2f (0, 0);
  glVertex2i (0, xrWidth);
  glTexCoord2f (1, 0);
  glVertex2i (xrWidth, xrWidth);
  glTexCoord2f (1, 1);
  glVertex2i (xrWidth, 0);
  glEnd ();

  glDisable (GL_TEXTURE_2D);

  /* Restore projections. */
  glMatrixMode (GL_MODELVIEW);
  glPopMatrix ();
  glMatrixMode (GL_PROJECTION);
  glPopMatrix ();

  return r;

#else /* DISABLE_VIDEO is set */
  return -1;
#endif
}
