/*
String computations on the graphics card.

Orion Sky Lawlor, olawlor@acm.org, 2005/2/20
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "ogl/ext.h"
#include "ogl/util.h"
#include "ogl/main.h"
#include "ogl/program.h"

#include "ogl/easylink.h"


const int wid=4; /* size of texture, 1D pixels */
GLenum tex=GL_TEXTURE_1D;

class myDrawable : public oglDrawable {
	GLuint texName;
public:
	myDrawable();
	void draw(const oglViewpoint &v);
};

/* Input data */
const char *in="My name is Sally";
int in_len=strlen(in); /* MUST be a power of two! */

myDrawable::myDrawable() {
// Texture unit 0: source data
	glActiveTextureARB(GL_TEXTURE0_ARB+0);
	
	// Upload input data to an OpenGL texture object:
	glGenTextures(1, &texName); // make texture object
	glBindTexture(tex, texName); // bound to unit 0
	gluBuild1DMipmaps( tex,
			GL_LUMINANCE8,
			in_len,
			GL_LUMINANCE,GL_UNSIGNED_BYTE,
			in );
	oglTextureType(oglTexture_nearest,tex);
	oglTexWrap(GL_CLAMP_TO_EDGE,tex);
	

// Texture unit 1: lookup table
	glActiveTextureARB(GL_TEXTURE0_ARB+1);
	// Fabricate a 1D lookup table:
	int t_len=128;
	unsigned char *t=new unsigned char[t_len];
	for (int i=0;i<t_len;i++) { 
		if (islower(i)) { /* Lowercase letters: uppercase */
			int c=i-'a';
			// c=(c+1)%26; /* rot1 encoding */
			t[i]=c+'A';
		}
		else t[i]=i;
	}
	
	// Upload input data to an OpenGL texture object:
	GLuint t_texName;
	glGenTextures(1, &t_texName); // make texture object
	glBindTexture(tex, t_texName); // bound to unit 1
	gluBuild1DMipmaps( tex,
			GL_LUMINANCE8,
			t_len,
			GL_LUMINANCE,GL_UNSIGNED_BYTE,
			t );
	oglTextureType(oglTexture_nearest,tex);
	oglTexWrap(GL_CLAMP_TO_EDGE,tex);
	
	glActiveTextureARB(GL_TEXTURE0_ARB+0);
	oglCheck("After texture upload.\n");
}

void myDrawable::draw(const oglViewpoint &v)
{
// Switch to a per-pixel coordinate system
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glTranslatef(-1,-1,0);
	glScaled(2.0/v.getWidth(),2.0/v.getHeight(),1.0); 
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	glBindTexture(tex, texName);
	glEnable(tex);
	glDisable(GL_BLEND);
	
// Draw a texture strip at the origin
	static oglProgram frag(
"!!ARBfp1.0\n"
"TEMP in, up;\n"
"TEX in, fragment.texcoord[0], texture[0], 1D;\n"
"MUL in, in, 2;\n" /* Shift from 0..255 brightness to a 0..127 table */
"TEX up, in, texture[1], 1D;\n"
"MAD result.color, up.r, 1.0, 0;\n"
"END"
); 
	int xi=1;
	frag.begin();
	glColor4f(1,1,1,1);
	glBegin(GL_QUADS);
	glTexCoord1d(0); glVertex3f(xi,0,0);
	glTexCoord1d(1); glVertex3f(xi+in_len,0,0);
	glTexCoord1d(1); glVertex3f(xi+in_len,1,0);
	glTexCoord1d(0); glVertex3f(xi,1,0);
	glEnd();
	frag.end();
	
// Read back the texture strip.
//  For performance, could use glCopyTexSubImage2D here
//  if reading back screen into another texture.
	int out_len=in_len;
	unsigned char *out=new unsigned char[out_len];
	glReadPixels(xi,0,out_len,1,GL_RED,GL_UNSIGNED_BYTE,out); /* only read red channel */
	for (int i=0;i<out_len;i++)
		printf("%02x ",out[i]);
	printf("\n");
	for (int i=0;i<out_len;i++)
		printf("%c ",out[i]);
	printf("\n");
	delete[] out;
	
// We're now done-- leave.
#ifdef WIN32
	printf("Program complete. Press any key to exit.\n");
	fgetc(stdin); /* Wait for a keypress */
#endif

	exit(0);
}

int main(int argc,char **argv) {
	oglOptions i("OpenGL Demo");
	i.lighting=false;
	i.fullscreen=false;
	i.clearColor=oglVector3d(0.2,0.3,0.4);
	i.width=1000;
	i.height=700;
	oglSetup(i);
	oglSetupExt();
	
	oglEventloop(new oglTrackballController,new myDrawable);
	return 0;
}

