/*
    texture2.c

    - Texture-Mapping, Textur wird aus Tiff-Datei gelesen.
    - Aufruf:  texture2 Tiff-Datei
      Dabei müssen Breite und Höhe der Tiff-Datei
      Zweier-Potenzen sein, also z.B. 128 oder 256.
      Tip: Für den GL-Kurs gibt es eine Datei test.tif.
    - !!! Achtung, beim Kompilieren und Linken wird die libtiff-Library
      benötigt, darum bitte das GNUmakefile neu laden (und das alte vorher
      bitte löschen).
    - Programm-Ende durch Drücken einer beliebigen Taste


    > GL-technisch ist hier nichts neues;
      aber wie würde man mit mehreren Texturen in einem
      Programm arbeiten? Man will ja nicht jedesmal
      die Texturen neu aus den Dateien laden.
      Lösung: Texture-Objekte; dazu gibt es (später) noch
      ein Beispiel texture3.c.

    > Tip: Man kann mit dem Bildprogramm 'xv' (Unix) evtl. vorhandene
      Bilddateien, etwa aus dem WWW, so bearbeiten, dass sie eine passende
      Grösse bekommen (durch ausschneiden oder skalieren) und dann
      im Tiff-Format abspeichern.
*/



# include       <stdio.h>
# include       <stdlib.h>
# include       <math.h>
# include       <tiffio.h>      /* Sam Leffler's libtiff library. */
# include       <GL/gl.h>
# include       <GL/glu.h>
# include       <GL/glut.h>



# define        FEHLER_ENDE(text, wert) \
                {  \
                    fprintf (stderr, text, wert);  \
                    fprintf (stderr, " (in %s, %d)\n", __FILE__, __LINE__);  \
                    exit (1);  \
                }

static int      textur_breite,
                textur_hoehe;
static GLubyte  *textur_pixels;



static void     display_func (void)
/*********************************/
{
    int         i,
                n = 8,
                h, b;
    float       x, y,
                phi,
                d;


    /* printf ("display_func()\n"); */

    /* Textur laden: */

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB,
        textur_breite, textur_hoehe, 0,
        GL_RGB, GL_UNSIGNED_BYTE, textur_pixels);

    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_DECAL);

    /* Rendern: */

    glLoadIdentity ();
    gluOrtho2D (-2, 2, -2, 2);

    glClearColor (1, 1, 1, 0);
    glClear (GL_COLOR_BUFFER_BIT);

    glPointSize (10);

    for (i = 0; i < n; i ++)
    {
        phi = 2 * M_PI * i / (float) n;
        x = cos (phi);
        y = sin (phi);
        d =  (i + 1) / (float) n;

        glColor3f (1, 1, 1);
        glEnable (GL_TEXTURE_2D);
        glBegin (GL_QUADS);
            glTexCoord2f (    0,     0);
              glVertex2f (    x,     y);

            glTexCoord2f (    1,     0);
              glVertex2f (x + d,     y);

            glTexCoord2f (    1,     1);
              glVertex2f (x + d, y + d);

            glTexCoord2f (    0,     1);
              glVertex2f (    x, y + d);
        glEnd ();
        glDisable (GL_TEXTURE_2D);

        glColor3f (0, 0, 0);
        glBegin (GL_POINTS);
            glVertex2f (x, y);
        glEnd ();
    }

    glFlush ();
    glutReportErrors ();
}



static void     keyboard_func (unsigned char key, int x, int y)
/*************************************************************/
{
    /* printf ("keyboard_func (key='%c', x=%d, y=%d)\n", key, x, y); */

    exit (0);
}



static void     tiff_bild_lesen (const char *dateiname,
                    GLubyte **gl_pixels, int *breite, int *hoehe)
/***************************************************************/
{
    char        fehlertext[1024];
    TIFF        *tiff_datei;
    TIFFRGBAImage
                tiff_bild;
    uint32      *tiff_pixels;
    int         n_pixels,
                i;


    /* Tiff-Datei öffnen und einlesen: */

    tiff_datei = TIFFOpen (dateiname, "r");
    if (tiff_datei == NULL)
        FEHLER_ENDE ("Datei '%s' kann nicht geöffnet werden", dateiname);

    if (TIFFRGBAImageBegin (&tiff_bild, tiff_datei, 0, fehlertext) == 0)
        FEHLER_ENDE ("Fehler beim Lesen der Tiff-Datei (%s)", fehlertext);

    n_pixels = tiff_bild.width * tiff_bild.height;
    *breite = tiff_bild.width;
    *hoehe = tiff_bild.height;

    tiff_pixels = _TIFFmalloc (n_pixels * sizeof (uint32));
    if (tiff_pixels == NULL)
        FEHLER_ENDE ("Fehler beim Anlegen der Tiff-Pixel", 0);

    if (TIFFRGBAImageGet (&tiff_bild, tiff_pixels, *breite, *hoehe) ==0)
        FEHLER_ENDE ("Fehler beim Lesen der Tiff-Datei", 0);

    TIFFRGBAImageEnd (&tiff_bild);


    /* Das Tiff-Bild steht jetzt in tiff_pixels (uint32).
       Es muss für OpenGl in GL_RGB-Pixels (GLubyte[3]) umgewandelt werden:
     */

    *gl_pixels = (GLubyte *) malloc (n_pixels * 3 * sizeof (GLubyte));
    if (gl_pixels == 0)
        FEHLER_ENDE ("Fehler beim Anlegen der GL-Pixel", 0);

    for (i = 0; i < n_pixels; i ++)
    {
        (*gl_pixels)[3 * i + 0] =  tiff_pixels[i]        & 0xff;
        (*gl_pixels)[3 * i + 1] = (tiff_pixels[i] >>  8) & 0xff;
        (*gl_pixels)[3 * i + 2] = (tiff_pixels[i] >> 16) & 0xff;
    }

    _TIFFfree (tiff_pixels);    /* Tiff-Bild wird nicht mehr gebraucht */
}



extern int      main (int argc, char **argv)
/******************************************/
{
    char        *programname,
                *dateiname;

    glutInit (&argc, argv);

    programname = argv[0];
    dateiname = argv[1];
    if (dateiname == 0)
        FEHLER_ENDE ("usage: %s tiff-datei", programname);

    tiff_bild_lesen (dateiname, &textur_pixels, &textur_breite, &textur_hoehe);


    /* Glut-Fenster, wie gehabt */

    glutInitDisplayMode (GLUT_RGB);

    glutInitWindowPosition (200, 100);
    glutInitWindowSize (600, 600);
    glutCreateWindow ("texture2");

    glutDisplayFunc (display_func);
    glutKeyboardFunc (keyboard_func);

    glutMainLoop ();

    return 0;
}

