PDA

View Full Version : Multitexture Problems....



jtibble
03-24-2011, 12:18 PM
Hello Everybody!

I'm working on a project that has some very curious and unique problems. I'm looking to apply the technique of multitexturing, but there are issues that seem to be preventing it form working.

THE STORY
I'm rendering lots of planar geometry (just once, not real-time). Depending on the world-coordinates of the geometry, it will be textured using one of 4 textures (top-left quarter of geometry gets texture 1, top-right gets texture 2, etc). The texture matrices are pre-computed and set up before the geometry is rendered, so there are no TexCoord() calls.

I want to set up and bind these 4 textures so multitexturing will work. As I understand it, if I have multitexturing set up correctly, and a vertex is rendered, the texture lookup will multiply the vertex's coordinates by the texture matrices to find the right texel. It will only ever be textured with one of the four textures.

BUT HERE'S THE TWIST...

The program makes extensive use of p-buffers and the WGL_DEPTH_COMPONENT_NV parameter. Before the geometry is rendered "for real" as described above, it is rendered into a "depth texture", which is a texture bound to the depth-component of a p-buffer that we can later use for depth-testing instead of the traditional z-buffer approach. Each "regular texture" has an associated depth texture. When the geometry is rendered, it is depth-tested against this depth texture first, then, if it satisfies the depth-test, it is rendered with the proper regular texture.

THE PROBLEM
When drawing the geometry, only the last-bound texture is used for rendering. I believe this is because of an issue of glActiveTexture calls.

When I go to enable each of the regular textures, I have to enable its associated depth texture. As I understand multitexturing, it uses the texture units starting with GL_TEXTURE0 up until the last texture unit that had been made active with glActiveTexture(). Obviously enabling and binding the texture units has to start with the regular textures (we don't want multitexturing to use the depth textures!), so I tried to assign the four regular textures to texture units GL_TEXTURE0 through GL_TEXTURE3, and the depth textures to texture units GL_TEXTURE5 through GL_TEXTURE8. My hope was that, by skipping texture unit GL_TEXTURE4, it would only use the four regular textures for multitexturing, but this is not the case. It only ever renders using the last-bound texture.

How do I multitexture when the images don't overlap, I don't specify texture coordinates, I need to bind four other textures to p-buffers as depth textures, and I can't use GLSL?

Any comments or help would be appreciated. If I didn't make something clear enough, please let me know and I'll do what I can to explain the situation further.

Thanks,
John

V-man
03-26-2011, 09:53 AM
You don't have a shader capable hardware? What does the hw report? Does it say GL 2.0? 1.5? 1.4? 1.3?
http://www.opengl.org/wiki/FAQ#How_do_I_tell_what_version_of_OpenGL_I.27m_usi ng.3F

I don't understand why you bind depth texture to GL_TEXTURE5 through GL_TEXTURE8. I don't understand what that part about p-buffer was with a WGL_DEPTH_COMPONENT_NV parameter.


I want to set up and bind these 4 textures so multitexturing will work. As I understand it, if I have multitexturing set up correctly, and a vertex is rendered, the texture lookup will multiply the vertex's coordinates by the texture matrices to find the right texel. It will only ever be textured with one of the four textures.

Vertices don't get rendered. Vertices get processed by the vertex processors which are at the front of the GPU pipeline.

The texture coordinate gets multiplied by the texture coordinate.


It will only ever be textured with one of the four textures.
I suggest that you look at some tutorials on multitexturing.

Post some code and specific questions. Try to keep your post clear.

mhagain
03-26-2011, 11:54 AM
You seem to have some fundamental misunderstandings about what multitexturing is and how it works, so I'll second the suggestion to step back, read up on the basics again (preferably with the help of a good tutorial and/or sample code), and get a basic implementation working (such as blending two textures over a single quad on-screen) before jumping into anything more advanced. You need to look at glActiveTexture, glTexEnv (for fixed functionality), glClientActiveTexture (if using vertex arrays or VBOs), glMultiTexCoord (if using immediate mode) and glGetIntegerv (GL_MAX_TEXTURE_UNITS);

Example code is avaialable here: http://www.codesampler.com/oglsrc/oglsrc_3.htm#ogl_multitexture

For what it's worth, there are so many things that could be wrong with what you're currently doing that it's difficult to even know where to start analysing it.

Is there any specific reason to not use GLSL, by the way? It can make the whole setup a lot more cleaner and easier, and enable you to explicitly specify how multiple textures are combined.

Dan Bartlett
03-26-2011, 12:05 PM
I just thought I'd mention that even OpenGL implementations that implement OpenGL 4.1 compatibility profile only need to provide 2 texture units for fixed function, so you may need to perform multiple passes anyway.

On my old card (NVidia Geforce 9500GT), GL_MAX_TEXTURE_UNITS = 4, but GL_MAX_TEXTURE_IMAGE_UNITS = 32. On my ATI laptop (Radeon Mobility HD 5650), GL_MAX_TEXTURE_UNITS = 8, GL_MAX_TEXTURE_IMAGE_UNITS = 16

jtibble
03-28-2011, 10:42 PM
Hi everybody, thanks for the replies.

The primary reason for not simply using GLSL is that the pipeline, the process, the rendering code for this program was inherited from a related predecessor program and is not easily replaced. We are running this on a Nvidia Quadro FX 4800 with 1.5GB of video RAM (because we have to store multiple-hundreds-of-megabytes-sized textures), so the hardware isn't an issue... only the time it would take to tear the program down and re-implement it using GLSL. I've checked the card's capabilities using GL_MAX_TEXTURE_UNITS, which returns 8, so if this was working there shouldn't be a need to render multiple passes.

@V-man, the primary reason I wanted to bind the depth textures to GL_TEXTURE5 through GL_TEXTURE8 was because, as I understood it, OpenGL would stream the geometry through the first four texture units sequentially if they were activated. Because I was trying to use texture units 0-3, I thought that maybe if I left 4 "deactivated" that the rendering pipeline wouldn't use texture units 5-8 to multitexture with. This is probably a bad assumption, but I'm hard-pressed to find examples of people using four textures simultaneously while keeping four others bound to p-buffers as depth. :)

If I was going to do multitexturing in the traditional, real-time environment (without these crazy depth maps and Nvidia-depth-binding commands), I would activate texture units 0-3 and set up my texture blending modes to (I believe) GL_ADD. However, because we do have these 4 extraneously-bound depth-textures that won't be rendered, I wanted to put them on texture units such that they wouldn't be used by OpenGL's multitexturing. The reason for choosing the GL_ADD blending mode is that, when the geometry is rendered, the four images will line up perfectly, edge-to-edge, and so there will be no need to interpolate between them.

Maybe I didn't explain this in my intro post, but the primary motivation for this conundrum is this: The process originally worked perfectly fine when texturing with a single, 300MB-ish texture. However, because of the OpenGL contexts being created and destroyed by the p-buffering depth-testing system, the program's heap was becoming fragmented. When the program tried to render/process the next set of geometry and tried to allocate another 300MB image, OpenGL would report an out-of-memory error. The solution was to split the image into fourths, copy them to the graphics card in turn, and then render using multitexture so as to avoid the cost of re-rendering the geometry four times, but alas, no luck so far.

Thanks again for the responses. If anyone has any other suggestions, I would like to hear them.

-John

BionicBytes
03-29-2011, 03:16 AM
as I understood it, OpenGL would stream the geometry through the first four texture units sequentially if they were activated.


I don't think you understand multitexturing. Geometry does not steam through texture units at all - more like the vertex processor(s).

The problem with your post is that I don't think anyone is able to understand what it is you are trying to do because it seems a little odd. Perhaps you need to take time out and try and explain exactly step by step what is supposed to happen and why you have these depth textures bound to texture units. Perhaps even attempt to re-write your algorithum as pseudo code so we can follow the process....

jtibble
03-29-2011, 10:42 AM
I don't think you understand multitexturing. Geometry does not steam through texture units at all - more like the vertex processor(s).


Haha, I keep typing that incorrectly. I do understand how the multitexturing works, I just keep writing that wrong.


As for pseudocode, here we go:

Program Begins.
Load 250MB image (texture)
Load 160MB image (heightmap)
Geometry is generated from heightmap image
Texture is split into fourths and copied to the graphics card
Math happens to generate texture coordinates for each texture "piece"
For each texture piece,
--A p-buffer is created
--A 2048x2048 "depth texture" is created and bound to the depth component of the p-buffer
--The geometry for that texture piece is rendered into the p-buffer to build a depth image. It is rendered from an oblique angle that matches the angle the original texture was created. This is used for depth-testing later.


Rendering loop begins**
For all tiles in final rendered output,
--Enable all geometry textures and depth-texture-bound-p-buffers
--Render the geometry from orthographic perspective***
--Store the rendered tile for later
--Disable all textures and p-buffers

Write all rendered tiles together into image file
Program exits (moves on to the next image/heightmap combination and repeats)


** The geometry when rendered and textured is much too large to be adequately represented by a single z-buffer (not enough precision), so when the main rendering loop happens, it renders the geometry in tiles which are later re-combined when written to the final output file


*** When the geometry is rendered, some peculiar things need to be done: The depth of the geometry is compared to the depth stored in the various depth-textures. If the depth of the rendered geometry is greater than the depth of the corresponding part of the depth texture, it will not be rendered. The idea is that if there is any geometry that is occluded (not represented in the original oblique-angled texture), it will not be rendered.

aleph31
04-14-2011, 07:48 AM
Taking a different approach for your problem: have you tried with other heap managers? I've recently used this one:

http://www.hoard.org/

And it helped with some issues regarding memory deallocation -don't know whether it will be of help for your fragmentation problem.

V-man
04-14-2011, 08:41 AM
Multitexturing works by activating the texture units.
For 4 texture units, it would look something like this

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(..........);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(..........);

glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(..........);

glActiveTexture(GL_TEXTURE3);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID0);
glTexEnvi(..........);

AND DISABLE 2D texturing on THE OTHER UNITS (By default, they are disabled)
glActiveTexture(GL_TEXTURE4);
glDisable(GL_TEXTURE_2D);

there is no need to bind depth texture to unit 5 through 8. I still don't understand that part but it is your code and you know what you are doing.

For examples of multitexturing (2 units)
http://www.opengl.org/wiki/Texture_Combiners

jtibble
04-14-2011, 10:42 AM
Hi again everybody.

I've got some sample code that, if I can just get it to work, will solve all my issues. I'm trying to draw a quad with two non-overlapping textures applied, one blue and one green. The blue should be textured on the left-half of the quad, and the green on the right-half. However, OpenGL textures both across the entire quad and blends them with GL_ADD to be cyan. If you can take a look at the code below (start at the hook() function) and give me some feedback, I'd really appreciate it.

Thanks!
-John


void setFrustum(GLdouble fovy, GLdouble aspect,
GLdouble zNear, GLdouble zFar,
bool leftHalf, bool rightHalf)
{
GLdouble xmin, xmax, ymin, ymax;



ymax = zNear * tan(fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;

if(leftHalf && !rightHalf)
{
xmax = 0.0;
}
else if(!leftHalf && rightHalf)
{
xmin = 0.0;
}

glMatrixMode(GL_PROJECTION_MATRIX);
glLoadIdentity();
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}



void textureGenerate(GLfloat* viewModelview, GLfloat* viewProjection)
{
// Texture matrix for view texture
GLfloat textureMatrix[16];

// Set up texture matrix for shadow map projection,
// which will be rolled into the eye linear
// texture coordinate generation plane equations
GLfloat tempMatrix[16] = { 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f };

m3dMatrixMultiply44(textureMatrix, tempMatrix, viewProjection);
m3dMatrixMultiply44(tempMatrix, textureMatrix, viewModelview);

// transpose to get the s, t, r, and q rows for plane equations
m3dTransposeMatrix44(textureMatrix, tempMatrix);

//copy the matrix to OpenGL
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
glTexGenfv(GL_S, GL_EYE_PLANE, &textureMatrix[0]);
glTexGenfv(GL_T, GL_EYE_PLANE, &textureMatrix[4]);
glTexGenfv(GL_R, GL_EYE_PLANE, &textureMatrix[8]);
glTexGenfv(GL_Q, GL_EYE_PLANE, &textureMatrix[12]);

}


void hook()
{
WglWindowOpenGLContextClass* windowContext = new WglWindowOpenGLContextClass();
windowContext->getOpenGLContext( 256,
256,
256,
true );


// Set background clearing color to 50% gray
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

glMatrixMode(GL_PROJECTION_MATRIX);
glLoadIdentity();

GLdouble fovy, aspect, zNear, zFar;
fovy = 10.4;
aspect = 1.0;
zNear = 1.0;
zFar = 10.1;

setFrustum(fovy, aspect, zNear, zFar, false, false);
//Copy the modelview matrix to an array to put into viewtexture pieces
GLfloat totalPerspective[16];
glGetFloatv(GL_PROJECTION_MATRIX, totalPerspective);

glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();
gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

//Pull out modelview matrix. This won't change between texture pieces
GLfloat* viewModelview = new GLfloat[16];
glGetFloatv(GL_MODELVIEW_MATRIX, viewModelview);



//Make sample texture (6x6 pixels, black cross on white)
int imageWidth, imageHeight;
imageWidth = imageHeight = 6;

//The Left image is all blue, the Right image is all green
//They should appear next to each other but instead are blended
GLfloat* halfImageLeft = new GLfloat[3*imageHeight*imageWidth/2];
GLfloat* halfImageRight = new GLfloat[3*imageHeight*imageWidth/2];

for(int x=0; x<imageHeight; x++)
{
for(int y=0; y<imageWidth/2; y++)
{
int bit = 3*(x*imageWidth/2 + y);
halfImageLeft[bit] = 0.0f;
halfImageLeft[bit+1] = 0.0f;
halfImageLeft[bit+2] = 1.0f;

halfImageRight[bit] = 0.0f;
halfImageRight[bit+1] = 1.0f;
halfImageRight[bit+2] = 0.0f;
}
}



//Allocate space for our projection matrices
GLfloat* viewProjection = new GLfloat[16];


/////////////////////
//Set up two textures
/////////////////////


glEnable(GL_TEXTURE_2D);

//HalfImageLeft
GLuint textureNumber[2];
glGenTextures(2, textureNumber);

glBindTexture(GL_TEXTURE_2D, textureNumber[0]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D( GL_TEXTURE_2D,
0,
GL_RGB,
imageWidth/2, imageHeight,
0,
GL_RGB,
GL_FLOAT,
halfImageLeft);

//Set the frustum to be the left-half of the full frustum
setFrustum(fovy, aspect, zNear, zFar, true, false);
glGetFloatv(GL_PROJECTION_MATRIX, viewProjection);
glActiveTexture(GL_TEXTURE0);
textureGenerate(viewModelview, viewProjection);




//HalfImageRight
glBindTexture(GL_TEXTURE_2D, textureNumber[1]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D( GL_TEXTURE_2D,
0,
GL_RGB,
imageWidth/2, imageHeight,
0,
GL_RGB,
GL_FLOAT,
halfImageRight);

//Set the frustum to be the right half of the full frustum
setFrustum(fovy, aspect, zNear, zFar, false, true);
glGetFloatv(GL_PROJECTION_MATRIX, viewProjection);
glActiveTexture(GL_TEXTURE1);
textureGenerate(viewModelview, viewProjection);




/////////////////////
//Set up Multitexturing
/////////////////////

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureNumber[0]);
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureNumber[1]);

glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);

glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );

glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );




/////////////////////
//DRAW QUAD
/////////////////////
glMatrixMode(GL_PROJECTION_MATRIX);
glLoadIdentity();
setFrustum(fovy, aspect, zNear, zFar, false, false);

glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();

//red quad for reference
glColor3f(1.0f, 0.0f, 0.0f);

glBegin(GL_QUADS);
glVertex3f(-0.95f, 0.95f, 0.0f);
glVertex3f(0.95f, 0.95f, 0.0f);
glVertex3f(0.95f, -0.95f, 0.0f);
glVertex3f(-0.95f, -0.95f, 0.0f);
glEnd();

gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

//present the quad to the screen
windowContext->swapBuffers();

V-man
04-15-2011, 07:04 AM
It is probably a question of having the right texture coordinates. You seem to be using TexGen and I have no idea what the result would be unless I take out my calculator....

Some mistakes I noticed
glMatrixMode(GL_PROJECTION_MATRIX);
glMatrixMode(GL_MODELVIEW_MATRIX);

The 2 lines above should generate an error.

You should have
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);

On the other hand, you are setting up the texture combiners correctly.

jtibble
04-15-2011, 01:07 PM
PLEASE NOTE: ALL THE PREVIOUS CODE IS GARBAGE

Please look at this post instead of the previous one.

I got my multitexturing to work, and here is the result. If you look for the gluLookAt() associated with the first texture, you will see that the call is "looking at" the origin (0,0,0). For the second texture, the call is "looking at" the point (0, 0.65, 0), which means that the texture should appear above the previous one, and yes, that is the case!

For more resources, please check out
Multitexture API Overview (http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node61.html)
OpenGL Sample Code (http://www.opengl.org/resources/code/samples/mjktips/projtex/index.html)
Siggraph 1999 EXTREMELY USEFUL SITE (http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node80.html)
http://www.codesampler.com/ (Bottom Tutorial + Code) (http://www.codesampler.com/usersrc/usersrc_6.htm)



WglWindowOpenGLContextClass* windowContext = new WglWindowOpenGLContextClass();
windowContext->getOpenGLContext( 256, 256, 256, true );


// Set background clearing color to 50% gray
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

GLdouble fovy, aspect, zNear, zFar;
fovy = 10.4;
aspect = 1.0;
zNear = 1.0;
zFar = 10.1;

glMatrixMode(GL_PROJECTION);

//setFrustum(fovy, aspect, zNear, zFar, false, false);
gluPerspective(fovy*2, aspect, zNear, zFar);

//Copy the modelview matrix to an array to put into viewtexture pieces
GLfloat totalPerspective[16];
glGetFloatv(GL_PROJECTION_MATRIX, totalPerspective);

for(int x=0; x<16; x++)
cout << totalPerspective[x] << " ";
cout << endl;

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

//Pull out modelview matrix. This won't change between texture pieces
GLfloat* viewModelview = new GLfloat[16];
glGetFloatv(GL_MODELVIEW_MATRIX, viewModelview);



//Make sample texture (6x6 pixels, black cross on white)
int imageWidth, imageHeight;
imageWidth = 6;
imageHeight = 6;

//The Left image is all blue, the Right image is all green
//They should appear next to each other but instead are blended
GLfloat* imageBlue = new GLfloat[3*imageHeight*imageWidth];
GLfloat* imageGreen = new GLfloat[3*imageHeight*imageWidth];

for(int x=0; x<imageHeight; x++)
{
for(int y=0; y<imageWidth; y++)
{
int bit = 3*(x*imageWidth + y);
imageBlue[bit] = 0.0f;
imageBlue[bit+1] = 0.0f;
imageBlue[bit+2] = 1.0f;

imageGreen[bit] = 0.0f;
imageGreen[bit+1] = 1.0f;
imageGreen[bit+2] = 0.0f;

}
}





//Allocate space for our projection matrices
GLfloat* viewProjection = new GLfloat[16];
GLfloat borderColor[] = {1.0f, 1.0f, 1.0f, 1.0f};


/////////////////////
//Set up texture 1
/////////////////////



GLuint textureNumber[2];
glGenTextures(2, textureNumber);

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);

glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

glBindTexture(GL_TEXTURE_2D, textureNumber[0]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glTexImage2D( GL_TEXTURE_2D,
0,
GL_RGB,
imageWidth, imageHeight,
0
GL_RGB,
GL_FLOAT,
imageBlue);

//Set texture matrix
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5f,0.5f,0.0f); //Bias
glScalef(0.5f,0.5f,1.0f); //Scale
glFrustum(-0.25, 0.25, -0.25, 0.25, 9.9, 10.1); //MV for light map
gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

//copy the matrix to OpenGL
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
GLfloat eyePlaneS[] = {1.0f, 0.0f, 0.0f, 0.0f};
GLfloat eyePlaneT[] = {0.0f, 1.0f, 0.0f, 0.0f};
GLfloat eyePlaneR[] = {0.0f, 0.0f, 1.0f, 0.0f};
GLfloat eyePlaneQ[] = {0.0f, 0.0f, 0.0f, 1.0f};

glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_S,GL_EYE_PLANE,eyePlaneS);
glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_T,GL_EYE_PLANE,eyePlaneT);
glTexGeni(GL_R,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_R,GL_EYE_PLANE,eyePlaneR);
glTexGeni(GL_Q,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_Q,GL_EYE_PLANE,eyePlaneQ);



/////////////////////
//Set up texture 2
/////////////////////

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);

glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

glBindTexture(GL_TEXTURE_2D, textureNumber[1]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glTexImage2D( GL_TEXTURE_2D,
0,
GL_RGB,
imageWidth, imageHeight,
0,
GL_RGB,
GL_FLOAT,
imageGreen);

//Set texture matrix
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5f,0.5f,0.0f); //Bias
glScalef(0.5f,0.5f,1.0f); //Scale
glFrustum(-0.25, 0.25, -0.25, 0.25, 9.9, 10.1); //MV for light map
glEnable(GL_TEXTURE_GEN_Q);

glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_S,GL_EYE_PLANE,eyePlaneS);
glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_T,GL_EYE_PLANE,eyePlaneT);
glTexGeni(GL_R,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_R,GL_EYE_PLANE,eyePlaneR);
glTexGeni(GL_Q,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR);
glTexGenfv(GL_Q,GL_EYE_PLANE,eyePlaneQ);




/////////////////////
//DRAW QUAD
/////////////////////
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);


//red quad for reference
glColor3f(1.0f, 1.0f, 1.0f);

glBegin(GL_QUADS);
glVertex3f(-0.95f, 0.95f, 0.0f);
glVertex3f(0.95f, 0.95f, 0.0f);
glVertex3f(0.95f, -0.95f, 0.0f);
glVertex3f(-0.95f, -0.95f, 0.0f);
glEnd();


//present the quad to the screen
windowContext->swapBuffers();