/*
 * Test cylindrical texcoord wrapping
 */


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>

static int Win;
static int WinWidth = 600, WinHeight = 400;
static GLfloat Xrot = 0, Yrot = 0;
static GLboolean CylWrap = GL_TRUE;
static GLboolean Lines = GL_FALSE;



static void
PrintString(const char *s)
{
   while (*s) {
      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
      s++;
   }
}


static void
DrawSample(GLboolean wrap)
{
   float p;

   glEnable(GL_TEXTURE_2D);

   if (Lines) {
      /* texured lines */
      float t;
      for (t = 0; t <= 1.0; t += 0.125) {
         float y = -1.0 + 2.0 * t;
         glBegin(GL_LINE_STRIP);
         for (p = 0.0; p <= 1.001; p += 0.05) {
            float x = -2.0 + p * 4.0;
            float s = p + 0.5;
            if (wrap && s > 1.0)
               s -= 1.0;
            glTexCoord2f(s, t);  glVertex2f(x, y);
         }
         glEnd();
      }
   }
   else {
      /* texured quads */
      glBegin(GL_QUAD_STRIP);
      for (p = 0.0; p <= 1.001; p += 0.1) {
         float x = -2.0 + p * 4.0;
         float s = p + 0.5;
         if (wrap && s > 1.0)
            s -= 1.0;
         glTexCoord2f(s, 0);  glVertex2f(x, -1);
         glTexCoord2f(s, 1);  glVertex2f(x, +1);
      }
      glEnd();
   }

   glDisable(GL_TEXTURE_2D);

   /* hash marks */
   glColor3f(0,0,0);
   glBegin(GL_LINES);
   for (p = 0.0; p <= 1.001; p += 0.1) {
      float x = -2.0 + p * 4.0;
      glVertex2f(x, -1.1);
      glVertex2f(x, -0.8);
   }
   glEnd();

   /* labels */
   glColor3f(1,1,1);
   for (p = 0.0; p <= 1.001; p += 0.1) {
      char str[100];
      float x = -2.0 + p * 4.0;
      float s = p + 0.5;

      if (wrap && s > 1.0)
         s -= 1.0;

      sprintf(str, "%3.1f", s);
      glRasterPos2f(x, -1.2);
      glBitmap(0, 0, 0, 0, -11, 0, NULL);
      PrintString(str);
      if (p == 0.0) {
         glBitmap(0, 0, 0, 0, -55, 0, NULL);
         PrintString("s =");
      }
   }
}


static void
Draw(void)
{
   glClear(GL_COLOR_BUFFER_BIT);

   glPushMatrix();
      glRotatef(Xrot, 1, 0, 0);
      glRotatef(Yrot, 0, 1, 0);

      glPushMatrix();
         glTranslatef(0, +1.2, 0);
         DrawSample(GL_FALSE);
      glPopMatrix();

      /* set Mesa back-door state for testing cylindrical wrap mode */
      if (CylWrap)
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 0.125);

      glPushMatrix();
         glTranslatef(0, -1.2, 0);
         DrawSample(GL_TRUE);
      glPopMatrix();

      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);

   glPopMatrix();

   glutSwapBuffers();
}


static void
Reshape(int width, int height)
{
   WinWidth = width;
   WinHeight = height;
   glViewport(0, 0, width, height);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glFrustum(-1.0, 1.0, -1.0, 1.0, 3.0, 25.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glTranslatef(0.0, 0.0, -10.0);
}


static void
Key(unsigned char key, int x, int y)
{
   (void) x;
   (void) y;
   switch (key) {
   case 'c':
   case 'C':
      CylWrap = !CylWrap;
      if (CylWrap)
         printf("Cylindrical wrap on.\n");
      else
         printf("Cylindrical wrap off.\n");
      break;
   case 'l':
   case 'L':
      Lines = !Lines;
      break;
   case 27:
      glutDestroyWindow(Win);
      exit(0);
      break;
   }
   glutPostRedisplay();
}


static void
SpecialKey(int key, int x, int y)
{
   const GLfloat step = 3.0;
   (void) x;
   (void) y;
   switch (key) {
   case GLUT_KEY_UP:
      Xrot -= step;
      break;
   case GLUT_KEY_DOWN:
      Xrot += step;
      break;
   case GLUT_KEY_LEFT:
      Yrot -= step;
      break;
   case GLUT_KEY_RIGHT:
      Yrot += step;
      break;
   }
   glutPostRedisplay();
}


static void
MakeSineWaveTexture(void)
{
   GLubyte tex[128][512][4];
   int i, j;

   for (j = 0; j < 128; j++) {
      for (i = 0; i < 512; i++) {
         float x = i / 511.0 * 2.0 * M_PI + M_PI * 0.5;
         float y0 = sin(x) * 0.5 + 0.5;
         int jy0 = y0 * 128;
         float y1 = sin(x + M_PI) * 0.5 + 0.5;
         int jy1 = y1 * 128;
         if (j < jy0)
            tex[j][i][0] = 0xff;
         else
            tex[j][i][0] = 0;
         if (j < jy1)
            tex[j][i][1] = 0xff;
         else
            tex[j][i][1] = 0;
         tex[j][i][2] = 0;
         tex[j][i][3] = 0xff;
      }
   }

   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 128, 0,
                GL_RGBA, GL_UNSIGNED_BYTE, tex);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}


static void
Init(void)
{
   glBindTexture(GL_TEXTURE_2D, 5);
   MakeSineWaveTexture();

   glClearColor(0.5, 0.5, 0.5, 0.0);
   glPointSize(3.0);

   printf("Press 'c' to toggle cylindrical wrap mode.\n");
   printf("Press 'l' to toggle line / quad drawing.\n");
}


int
main(int argc, char *argv[])
{
   glutInit(&argc, argv);
   glutInitWindowSize(WinWidth, WinHeight);
   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
   Win = glutCreateWindow(argv[0]);
   glutReshapeFunc(Reshape);
   glutSpecialFunc(SpecialKey);
   glutKeyboardFunc(Key);
   glutDisplayFunc(Draw);
   Init();
   glutMainLoop();
   return 0;
}