
/*
 * matrix.c -- A simple example showing two ways to do matrix multiplication.
 * (a) OpenGL  and (b) UA vision library (kjb). 
 */

/*
 * In CS433/533 you can use any system like for basic matrix manipulation
 * including the two shown here, your own, or one of many standard ones
 * available on the web. The kjb library way is designed for simplified memeory
 * management and performance in certain circumstances. 
 *
 * If you want to use the kjb library, add ~kobus/doc/man to your MANPATH, and
 * do a "man kjb".
*/

/* Include for kjb matrix stuff. Best to be first if used. Includes stuff like
 * stdio.h and stdlib.h (but NOT any OpenGL/GLUT stuff!). 
*/
#include "m/m_incl.h"    /* Must be first. */

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

/* -------------------------------------------------------------------------- */

static int demo_matrix_multiply_with_opengl(int argc, char* argv[]);
static int demo_matrix_multiply_with_kjb(void);

/* -------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------- */

int main(int argc, char *argv[])
{

    /* Sample code for OpenGL.  */
    if (demo_matrix_multiply_with_opengl(argc, argv) != 0)
    {
        return EXIT_FAILURE; 
    }

    /* Sample code for kjb library.  */
    if (demo_matrix_multiply_with_kjb() == ERROR)
    {
        kjb_print_error(); 
        return EXIT_FAILURE; 
    }

    return EXIT_SUCCESS;
}

/*  /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\   */

/*
// Example of getting OpenGL to multiply matrices for us. It seems we need to
// have a window created. It is also important not to disturb the stack, so we
// push, do our stuff, and then pop.
*/

static int demo_matrix_multiply_with_opengl(int argc, char* argv[])
{
    int win;
    int i,j; 
    GLfloat matrix[16]; 
    GLfloat matrix_2[16] = {2,0,1,0,  /* This represents columns in sequence. */ 
                            0,3,0,3,  /* Thus the matrix is TRANSPOSE of that */
                            0,0,4,0,  /* suggested by the formatting. */
                            1,0,0,5}; /* (Fortran legacy). */

    /* Note that this is a permutation matrix that switches columns according to
     * the pattern in the matrix. */
    GLfloat matrix_3[ 16 ] = {0,0,1,0, /* This reoresents columns in sequence. */ 
                             0,0,0,1,  /* Thus the matrix is TRANSPOSE of that */
                             1,0,0,0,  /* suggested by the formatting. */
                             0,1,0,0}; /* (Fortran legacy). */

    glutInit(&argc, argv);                /* initialize GLUT system */

    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);

    glutInitWindowSize(400,5000);          /* width, height */

    win = glutCreateWindow("Dummy");   /* create window */

    /* From this point on the current window is win */

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadMatrixf(matrix_2);
    glMultMatrixf(matrix_3);
    glGetFloatv(GL_MODELVIEW_MATRIX, matrix);

    printf("Result with OpenGL.\n\n"); 

    for (i = 0; i < 4; i++)
    {
        for (j = 0; j <4; j++)
        {
            printf("%f ", matrix[j*4+i]);
        }
        printf("\n");
    }

    printf("\n");

    glPopMatrix();

    return 0;
}

/*  /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\   */

static int demo_matrix_multiply_with_kjb()
{
    Matrix* a_mp   = NULL;      /* MUST init to NULL. */
    Matrix* b_mp   = NULL;      /* MUST init to NULL. */
    Matrix* c_mp   = NULL;      /* MUST init to NULL. */
    int     result = NO_ERROR;


    if (    (get_zero_matrix(&a_mp, 4, 4) == ERROR) 
         || (get_zero_matrix(&b_mp, 4, 4) == ERROR)
       )
    {
        result = ERROR; 
    }
    else
    {
        /* Fill in the same test values as before. */

        a_mp->elements[ 0 ][ 0 ] = 2.0;
        a_mp->elements[ 2 ][ 0 ] = 1.0;
        a_mp->elements[ 1 ][ 1 ] = 3.0;
        a_mp->elements[ 3 ][ 1 ] = 3.0;
        a_mp->elements[ 2 ][ 2 ] = 4.0;
        a_mp->elements[ 0 ][ 3 ] = 1.0;
        a_mp->elements[ 3 ][ 3 ] = 5.0;

        /* 
         * Note that this is a permutation matrix that switches columns
         * according to the pattern in the matrix. 
        */
        b_mp->elements[ 2 ][ 0 ] = 1.0;
        b_mp->elements[ 3 ][ 1 ] = 1.0;
        b_mp->elements[ 0 ][ 2 ] = 1.0;
        b_mp->elements[ 1 ][ 3 ] = 1.0;

        result = multiply_matrices(&c_mp, a_mp, b_mp); 
    }

    /*
     * Writes don't fail often, but untested return values make me
     * uncomfortable.
    */

    if (result != ERROR)
    {
        result = kjb_puts("\nResult using kjb library. The write routine writes integral doubles as integers.\n\n"); 
    }

    if (result != ERROR)
    {
        result = write_matrix(c_mp, NULL);  /* NULL means stdout. */
    }

    if (result != ERROR)
    {
        result = kjb_puts("\n"); 
    }

    free_matrix(a_mp);    /* Free is OK, even if argument is NULL. */
    free_matrix(b_mp);    /* Free is OK, even if argument is NULL. */
    free_matrix(c_mp);    /* Free is OK, even if argument is NULL. */

    return result; 
}



