/**
 * Sample multi-touch program that displays a square where a cursor
 * clicks, with a different color for each cursor.
 *
 * Copyright (C) 2012  Sylvain Beucler
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

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

#include <GL/freeglut.h>
#include <GL/gl.h>

#define NUM_DEVICES 16
#define NUM_CURSORS 64
typedef struct cursor {
    char on;
    float x;
    float y;
} *Cursor;
struct cursor cursors[NUM_DEVICES][NUM_CURSORS];


static float square[] = {
        -.5, -.5,
         .5, -.5,
        -.5,  .5,
         .5,  .5,
    };

void onDisplay(void) {
    int d;
    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, GL_FLOAT, 0, square);
    for (d = 0; d < NUM_DEVICES; d++) {
        int c;
        for (c = 0; c < NUM_CURSORS; c++) {
            Cursor C = &cursors[d][c];
            if (C->on) {
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
                glTranslatef(C->x, C->y, 0);
                glScalef(30, 30, 1);
                
                switch(c) {
                case 0:
                    glColor4f(0,0,1,1);
                    break;
                case 1:
                    glColor4f(0,1,0,1);
                    break;
                case 2:
                    glColor4f(1,0,0,1);
                    break;
                case 3:
                    glColor4f(1,1,1,1);
                    break;
                default:
                    glColor4d(.5,.5,.5,1);
                    break;
                }
                glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            }
        }
    }
    glDisableClientState(GL_VERTEX_ARRAY);

    glutSwapBuffers();
}

void onMouse(int button, int state, int x, int y) {
    if (button == 0) {
        cursors[0][0].on = (state == GLUT_DOWN);
        cursors[0][0].x = (float)x;
        cursors[0][0].y = (float)y;
        printf("normal click\n");
    }
}

void onMotion(int x, int y) {
    cursors[0][0].x = (float)x;
    cursors[0][0].y = (float)y;
}

/* Using FG2.8 (reversed) prototype for now */
/* void onMultiButton(int cursor_id, int button, int state, int x, int y) { */
void onMultiButton(int cursor_id, int x, int y, int button, int state) {
    if (cursor_id >= NUM_CURSORS) {
        fprintf(stderr, "cursor_id (%d) >= NUM_CURSORS (%d), out of slots\n", cursor_id, NUM_CURSORS);
        return;
    }
    if (button == 0) {
        cursors[0][cursor_id].on = (state == GLUT_DOWN);
        cursors[0][cursor_id].x = (float)x;
        cursors[0][cursor_id].y = (float)y;
        printf("multi-touch %d click\n", cursor_id);
    }
}

void onMultiMotion(int cursor_id, int x, int y) {
    if (cursor_id >= NUM_CURSORS) {
        fprintf(stderr, "cursor_id (%d) >= NUM_CURSORS (%d), out of slots\n", cursor_id, NUM_CURSORS);
        return;
    }
    cursors[0][cursor_id].x = (float)x;
    cursors[0][cursor_id].y = (float)y;
}

void onReshape(int width, int height) {
    glViewport(0, 0, width, height);
    
    glMatrixMode(GL_PROJECTION);
    glOrtho(0, width, height, 0, -1, 1);
}

void onIdle(void) {
    glutPostRedisplay();
}

int main(int argc, char* argv[]) {
    memset(cursors, 0, sizeof(cursors));

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
    glutInitWindowSize(640, 480);
    glutCreateWindow("Multi-touch test");

    glutDisplayFunc(onDisplay);
    glutReshapeFunc(onReshape);
    glutIdleFunc(onIdle);
    glutMouseFunc(onMouse);
    glutMotionFunc(onMotion);
    glutMultiButtonFunc(onMultiButton);
    glutMultiMotionFunc(onMultiMotion);

    glutMainLoop();

    return EXIT_SUCCESS;
}
