GLuint texture[3]; // Storage For 3 Textures
GLuint bump[3]; // Our Bumpmappings
GLuint invbump[3]; // Inverted Bumpmaps
GLuint glLogo; // Handle For OpenGL-Logo
GLuint multiLogo; // Handle For Multitexture-Enabled-Logo
GLfloat LightAmbient[] = { 0.2f, 0.2f, 0.2f}; // Ambient Light Is 20% White
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f}; // Diffuse Light Is White
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f}; // Position Is Somewhat In Front Of Screen
GLfloat Gray[] = { 0.5f, 0.5f, 0.5f, 1.0f};
The next block of code contains the numerical representation of a textured cube built out of GL_QUADS. Each five numbers specified represent one set of 2D-texture-coordinates one set of 3D-vertex-coordinates. This is to build the cube using for-loops, since we need that cube several times. The data-block is followed by the well-known WndProc()-prototype from former lessons.
// Data Contains The Faces Of The Cube In Format 2xTexCoord, 3xVertex.
// Note That The Tesselation Of The Cube Is Only Absolute Minimum.
GLfloat data[]= {
// FRONT FACE
0.0f, 0.0f, –1.0f, –1.0f, +1.0f,
1.0f, 0.0f, +1.0f, –1.0f, +1.0f,
1.0f, 1.0f, +1.0f, +1.0f, +1.0f,
0.0f, 1.0f, –1.0f, +1.0f, +1.0f,
// BACK FACE
1.0f, 0.0f, –1.0f, –1.0f, –1.0f,
1.0f, 1.0f, –1.0f, +1.0f, –1.0f,
0.0f, 1.0f, +1.0f, +1.0f, –1.0f,
0.0f, 0.0f, +1.0f, –1.0f, –1.0f,
// Top Face
0.0f, 1.0f, –1.0f, +1.0f, –1.0f,
0.0f, 0.0f, –1.0f, +1.0f, +1.0f,
1.0f, 0.0f, +1.0f, +1.0f, +1.0f,
1.0f, 1.0f, +1.0f, +1.0f, –1.0f,
// Bottom Face
1.0f, 1.0f, –1.0f, –1.0f, –1.0f,
0.0f, 1.0f, +1.0f, –1.0f, –1.0f,
0.0f, 0.0f, +1.0f, –1.0f, +1.0f,
1.0f, 0.0f, –1.0f, –1.0f, +1.0f,
// Right Face
1.0f, 0.0f, +1.0f, –1.0f, –1.0f,
1.0f, 1.0f, +1.0f, +1.0f, –1.0f,
0.0f, 1.0f, +1.0f, +1.0f, +1.0f,
0.0f, 0.0f, +1.0f, –1.0f, +1.0f,
// Left Face
0.0f, 0.0f, –1.0f, –1.0f, –1.0f,
1.0f, 0.0f, –1.0f, –1.0f, +1.0f,
1.0f, 1.0f, –1.0f, +1.0f, +1.0f,
0.0f, 1.0f, –1.0f, +1.0f, –1.0f
};
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
The next block of code is to determine extension-support during run-time.
First, we can assume that we have a long string containing all supported extensions as '\n'-seperated sub-strings. So all we need to do is to search for a '\n' and start comparing string with search until we encounter another '\n' or until string doesn't match search anymore. In the first case, return a true for "found", in the other case, take the next sub-string until you encounter the end of string. You'll have to watch a little bit at the beginning of string, since it does not begin with a newline-character.
By the way: A common rule is to ALWAYS check during runtime for availability of a given extension!
bool isInString(char *string, const char *search) {
int pos=0;
int maxpos=strlen(search)-1;
int len=strlen(string);
char *other;
for (int i=0; i<len; i++) {
if ((i==0) || ((i>1) && string[i-1]=='\n')) { // New Extension Begins Here!
other=&string[i];
pos=0; // Begin New Search
while (string[i]!='\n') { // Search Whole Extension-String
if (string[i]==search[pos]) pos++; // Next Position
if ((pos>maxpos) && string[i+1]=='\n') return true; // We Have A Winner!
i++;
}
}
}
return false; // Sorry, Not Found!
}
Now we have to fetch the extension-string and convert it to be '\n'-separated in order to search it for our desired extension. If we find a sub-string "GL_ARB_multitexture" in it, this feature is supported. But we only can use it, if __ARB_ENABLE is also true. Last but not least we need GL_EXT_texture_env_combine to be supported. This extension introduces new ways how the texture-units interact. We need this, since GL_ARB_multitexture only feeds the output from one texture unit to the one with the next higher number. So we rather check for this extension than using another complex blending equation (that would not exactly do the same effect!) If all extensions are supported and we are not overridden, we'll first determine how much texture-units are available, saving them in maxTexelUnits. Then we have to link the functions to our names. This is done by the wglGetProcAdress()-calls with a string naming the function call as parameter and a prototype-cast to ensure we'll get the correct function type.
bool initMultitexture(void) {
char *extensions;
extensions=strdup((char *) glGetString(GL_EXTENSIONS)); // Fetch Extension String
int len=strlen(extensions);
for (int i=0; i<len; i++) // Separate It By Newline Instead Of Blank
if (extensions[i]==' ') extensions[i]='\n';
#ifdef EXT_INFO
MessageBox(hWnd,extensions, "supported GL extensions", MB_OK | MB_ICONINFORMATION);
#endif
if (isInString(extensions,"GL_ARB_multitexture") // Is Multitexturing Supported?
&& __ARB_ENABLE // Override Flag
&& isInString(extensions,"GL_EXT_texture_env_combine")) // texture-environment-combining supported?
{
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB,&maxTexelUnits);
glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC) wglGetProcAddress("glMultiTexCoord1fARB");
glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB");
glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC) wglGetProcAddress("glMultiTexCoord3fARB");
glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC) wglGetProcAddress("glMultiTexCoord4fARB");
glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB");
glClientActiveTextureARB= (PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress("glClientActiveTextureARB");
#ifdef EXT_INFO
MessageBox(hWnd, "The GL_ARB_multitexture extension will be used.", "feature supported!", MB_OK | MB_ICONINFORMATION);
#endif
return true;
}
useMultitexture=false; // We Can't Use It If It Isn't Supported!
return false;
}
InitLights() just initialises OpenGL-Lighting and is called by InitGL() later on.
void initLights(void) {
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Load Light-Parameters into GL_LIGHT1
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);