// Hello World in a shader.
// Kind of twisted, since it uses signed chars.
// Modern OpenGL, using my lab material for simplicity.

#include <stdio.h>
#include <OpenGL/gl3.h>
#include "MicroGlut.h"
#include "GL_utilities.h"
#include "loadobj.h"
#include <sys/times.h>
// Linking hint for Lightweight IDE:
// uses framework Cocoa

// Add offset (texUnit2) to string (texUnit)
// Negative values end up as > 0.5, adjust them!
static const char *fragSource =
{
"#version 150\n"
"uniform sampler2D texUnit;"
"uniform sampler2D texUnit2;"
"out vec4 outColor;"
"in vec2 texCoord;"
"void main(void)"
"{"
"   vec4 texVal  = texture(texUnit, texCoord);"
"   vec4 texVal2  = texture(texUnit2, texCoord);"
"   if (texVal2.r > 0.5) texVal2.r -= 1.0;"
"   if (texVal2.g > 0.5) texVal2.g -= 1.0;"
"   if (texVal2.b > 0.5) texVal2.b -= 1.0;"
"   if (texVal2.a > 0.5) texVal2.a -= 1.0;"
"   outColor = texVal + texVal2;\n"
"}"
};

// Vertex shader, pass position and texcoord
char *vs =
{
"#version 150\n"
"in  vec3 inPosition;"
"in vec2 inTexCoord;"
"out vec2 texCoord;"
"void main()"
"{"
"	texCoord = inTexCoord;"
"	gl_Position = vec4(inPosition, 1.0);"
"}"
};

GLfloat vertices[] = {	-1.0f,-1.0f,0.0f,
						-1.0f,1.0f,0.0f,
						1.0f,-1.0f,0.0f,
						1.0f,1.0f,0.0f };

GLfloat texcoord[] = {	0.0f, 1.0f,
						0.0f, 0.0f,
						1.0f, 1.0f,
						1.0f, 0.0f};
unsigned int indices[] = {0,1,2, 2,1,3};

Model *m;
GLuint shader;

// declare texture size, the actual data will be a vector 
// of size texSize*1*4 = N

#define N 16
// test data
char a[N] = "Hello \0\0\0\0\0\0\0\0\0\0";
char b[N] = {15, 10, 6, 0, -12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char c[N];
#define texSize 4

void display()
{
	DrawModel(m, shader, "inPosition", NULL, "inTexCoord");
	glutSwapBuffers();

	printf("%s",a);
    // and read back
    glReadPixels(0, 0, texSize, 1, GL_RGBA,GL_UNSIGNED_BYTE,c);
    // print out results
    printf("%s\n",c);
	exit(0);
}

// Not exported by GL_utilties:
GLuint compileShaders(const char *vs, const char *fs, const char *gs, const char *tcs, const char *tes,
								const char *vfn, const char *ffn, const char *gfn, const char *tcfn, const char *tefn);

GLuint LoadTexture(unsigned char *a, GLuint texunit)
{
    GLuint tex;
	glActiveTexture(texunit);
    glGenTextures (1, &tex);
    glBindTexture(GL_TEXTURE_2D,tex);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,
                 texSize,1,0,GL_RGBA,GL_UNSIGNED_BYTE, a);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	return tex;
}

int main(int argc, char **argv)
{
// set up glut to get valid GL context and 
// get extension entry points
    glutInit (&argc, argv);
	glutInitContextVersion(3, 2);
	glutInitWindowSize (4, 1);
    glutCreateWindow("TEST1");
    
// create string texture
    GLuint tex = LoadTexture(a, GL_TEXTURE0);
// create offset texture
    GLuint offtex = LoadTexture(b, GL_TEXTURE1);

// Compile shader
	shader = compileShaders(vs, fragSource, NULL, NULL, NULL, "vs", "fs", NULL, NULL, NULL);
	
// Inform shader of texture units
	glUniform1i(glGetUniformLocation(shader, "texUnit1"), 0); // Texture unit 0
	glUniform1i(glGetUniformLocation(shader, "texUnit2"), 1); // Texture unit 1
	
	m = LoadDataToModel(vertices, NULL, texcoord, NULL, indices, 4, 6);

// Ask for a redraw
	glutDisplayFunc(display); 
	glutMainLoop();
	exit(0);
}
