OpenGL:Tutorials:Tutorial Framework:Display Lists
From GPWiki(Redirected from OpenGL Tutorial Framework:Display Lists)
The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server. However, the GPWiki forums are still active! Come say hello.
[edit] What is a display list?Display lists are a way of bundling OpenGL commands for future execution. They can give a performance boost when construction of our objects involves calculation or other slow downs. Once our object data is in the display list, it can be recalled easily and without the calculation that was required to produce it. The other nice aspect of display lists is that they fit in with OpenGL's state system, we can change the texture, color, size or any aspect of the object that isn't explicitly defined in the list. [edit] Using Display ListsWe use the glGenLists() function to allocate storage for display lists: DListRoot=glGenLists(3); This is similar to generating texture storage except that the lists originate from the returned base point rather than the array used for textures. To access display list n we simply call: glCallList(DListRoot+n); To clean up or delete the lists we use: glDeleteLists(DListRoot,3);
[edit] An ExampleIn our example we are going to create display lists for three objects. These objects will then be displayed with different textures and scale factors to demonstrate the adjustments that are possible due to GL's state system.
typedef struct { float xPos,yPos,zPos,Rotate; int TexNum,ObjList; float Red,Green,Blue; float Scale,rVec; }ObjInfo; These parameters are initalised to random values: for(index=0;index<NUM_OBJ;++index) { Obj[index].xPos=((rand()%200)/5.0f)-20.0f; Obj[index].yPos=((rand()%200)/5.0f)-20.0f; Obj[index].zPos=((rand()%200)/5.0f)-20.0f; Obj[index].Scale=(rand()%11)/10.0f; Obj[index].Rotate=(float)(rand()%180); Obj[index].rVec=(float)((rand()%100)/200.0f)-0.25f; Obj[index].TexNum=rand()%2; Obj[index].ObjList=rand()%3; } An important note here is that scaling our object will scale all our geometery, including normals. This will change the lighting of the polygons. To stop this we use: glEnable(GL_NORMALIZE); Which prevents scaling from changing our normal lengths.
DListRoot=glGenLists(3); The actual compilation of the lists can occur anywhere, but here we'll separate it into three functions, BuildCube(),BuildDiamond() and BuildStar(). These functions build some simple objects. Looking at the functions, we can see that most of the code is pretty standard OpenGL, we are specifing UV and vertex coords in the usual way. The only difference is that the call to glNewList() means that we are storing the instructions rather than rendering the polygons. glNewList(ListID,GL_COMPILE); // OpenGL code here glEndList(); The GL_COMPILE flag tells OpenGL to store the instructions with no output, if we use GL_COMPILE_AND_EXECUTE the instructions will be stored and displayed. This can be useful for scenes where the geometery is rendered more than once per frame, e.g. when producing reflections.
Because our lists only specify UV coords, not textures, we are able to change the appearance of the objects easily. Our demo looks like this:
[edit] Source CodeThe source to Render.cpp, compile this demo using the OpenGL Tutorial Framework. #include "Framework.h" #include <ctime> #include <cmath> #include "tga.h" const int NUM_OBJ=2000; // Number of Objects // Vector structure typedef struct { float x,y,z; }stVec; // Object Structure typedef struct { float xPos,yPos,zPos,Rotate; int TexNum,ObjList; float Red,Green,Blue; float Scale,rVec; }ObjInfo; // Function declarations bool LoadTexture(char *TexName, GLuint TexHandle); stVec CalcNormal(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3); void BuildCube(GLuint ListID); void BuildDiamond(GLuint ListID); void BuildStar(GLuint ListID); void Render(void) { GLuint Texture[128]; // Handles to our textures ObjInfo Obj[NUM_OBJ]; // Object array GLuint DListRoot; // Display List float Rot=0.0f; // Rotation value for the observer int index; float view_height=600.0f/800.0f; // Allocate all textures in one go glGenTextures(128,Texture); // Setup our screen glViewport(0,0,800,600); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-0.5f,0.5f,-0.5f* view_height,0.5f*view_height, 1.0f, 500.0f); glMatrixMode(GL_MODELVIEW); glClearColor(0.0f,0.0f,0.0f,1.0f); // Enable z-buffer glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glEnable(GL_CULL_FACE); // Prevent scaling operations from affecting normal values glEnable(GL_NORMALIZE); // Load the textures LoadTexture("../Images/Logo.tga",Texture[0]); LoadTexture("../Images/lightbricks.tga",Texture[1]); // Allocate 3 display lists DListRoot=glGenLists(3); // Build the display lists BuildCube(DListRoot); BuildDiamond(DListRoot+1); BuildStar(DListRoot+2); // Seed the randomiser srand(time(NULL)); // Init the object parameters for(index=0;index<NUM_OBJ;++index) { Obj[index].xPos=((rand()%200)/5.0f)-20.0f; Obj[index].yPos=((rand()%200)/5.0f)-20.0f; Obj[index].zPos=((rand()%200)/5.0f)-20.0f; Obj[index].Scale=(rand()%11)/10.0f; Obj[index].Rotate=(float)(rand()%180); Obj[index].rVec=(float)((rand()%100)/200.0f)-0.25f; Obj[index].TexNum=rand()%2; Obj[index].ObjList=rand()%3; } // Set the general scene properties glColor4f(1.0f,1.0f,1.0f,1.0f); glEnable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // Main loop while(RunLevel) { if(Keys[VK_ESCAPE]) RunLevel=0; // Update the objects for(index=0;index<NUM_OBJ;++index) { Obj[index].Rotate+=Obj[index].rVec; } // Start the scene glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // Rotate the view glRotatef(Rot,0.0f,1.0f,0.0f); glRotatef(Rot,1.0f,0.0f,0.0f); // Draw the objects for(index=0;index<NUM_OBJ;++index) { glBindTexture(GL_TEXTURE_2D,Texture[Obj[index].TexNum]); glPushMatrix(); glTranslatef(Obj[index].xPos,Obj[index].yPos,Obj[index].zPos); glRotatef(Obj[index].Rotate,0.0f,0.2f,1.0f); glRotatef(Obj[index].Rotate,1.0f,0.0f,0.0f); glScalef(Obj[index].Scale,Obj[index].Scale,Obj[index].Scale); glCallList(DListRoot+Obj[index].ObjList); // Call the display list glPopMatrix(); } // Update the rotation value Rot+=0.01f; // Show our scene FlipBuffers(); } // Clean up glDeleteTextures(128,Texture); glDeleteLists(DListRoot,3); } // Load a TGA texture bool LoadTexture(char *TexName, GLuint TexHandle) { TGAImg Img; // Image loader // Load our Texture if(Img.Load(TexName)!=IMG_OK) return false; glBindTexture(GL_TEXTURE_2D,TexHandle); // Set our Tex handle as current // Create the texture if(Img.GetBPP()==24) glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0, GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg()); else if(Img.GetBPP()==32) glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0, GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg()); else return false; // Specify filtering and edge actions glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); return true; } void BuildCube(GLuint ListID) { glNewList(ListID,GL_COMPILE); glBegin(GL_QUADS); glNormal3f(0.0f,1.0f,0.0f); glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); // Draw bottom face glNormal3f(0.0f,-1.0f,0.0f); glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); // Side faces glNormal3f(0.0f,0.0f,1.0f); glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glNormal3f(1.0f,0.0f,0.0f); glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(1.0f,2.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(0.0f,2.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glNormal3f(0.0f,0.0f,-1.0f); glTexCoord2f(0.0f,2.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glTexCoord2f(0.0f,3.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(1.0f,3.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glTexCoord2f(1.0f,2.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glNormal3f(-1.0f,0.0f,0.0f); glTexCoord2f(1.0f,3.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glTexCoord2f(0.0f,3.0f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.0f,4.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(1.0f,4.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glEnd(); glEndList(); } void BuildDiamond(GLuint ListID) { glNewList(ListID,GL_COMPILE); stVec Norm; glBegin(GL_TRIANGLES); Norm=CalcNormal(-1.0f,0.0f,1.0f,0.0f, -1.0f, 0.0f,1.0f, 0.0f, 1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f); Norm=CalcNormal(-1.0f, 0.0f,-1.0f,0.0f,-1.0f,0.0f,-1.0f,0.0f,1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f); Norm=CalcNormal( 1.0f,0.0f,-1.0f,0.0f,-1.0f,0.0f,-1.0f, 0.0f,-1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f); Norm=CalcNormal(1.0f, 0.0f, 1.0f,0.0f,-1.0f,0.0f, 1.0f,0.0f,-1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f); Norm=CalcNormal( 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,-1.0f, 0.0f, 1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f); Norm=CalcNormal( 1.0f, 0.0f,-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f); Norm=CalcNormal(-1.0f, 0.0f,-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,-1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f); Norm=CalcNormal(-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f,-1.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f); glEnd(); glEndList(); } void BuildStar(GLuint ListID) { glNewList(ListID,GL_COMPILE); stVec Norm; glBegin(GL_TRIANGLES); Norm=CalcNormal(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.3f, 0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); glTexCoord2f(0.75f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f); Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.3f, 0.3f, 0.0f, 0.0f, 0.0f, 0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(0.75f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.3f,-0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); glTexCoord2f(0.75f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f); Norm=CalcNormal(0.0f,-1.0f, 0.0f, 0.3f,-0.3f, 0.0f, 0.0f, 0.0f, 0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(0.75f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); Norm=CalcNormal(0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.4f,-0.3f,-0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); glTexCoord2f(0.25f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f); Norm=CalcNormal(-1.0f, 0.0f, 0.0f,-0.3f,-0.3f, 0.0f, 0.0f, 0.0f, 0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.25f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); Norm=CalcNormal(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f,-0.3f, 0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); glTexCoord2f(0.25f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f); Norm=CalcNormal(0.0f, 1.0f, 0.0f,-0.3f, 0.3f, 0.0f, 0.0f, 0.0f, 0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.25f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f); Norm=CalcNormal(0.0f, 1.0f, 0.0f, 0.3f, 0.3f, 0.0f, 0.0f, 0.0f,-0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.25f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-0.4f, 0.3f, 0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); glTexCoord2f(0.25f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f); Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.3f,-0.3f, 0.0f, 0.0f, 0.0f,-0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(0.25f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); Norm=CalcNormal(0.0f,-1.0f, 0.0f, 0.0f, 0.0f,-0.4f, 0.3f,-0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); glTexCoord2f(0.25f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f); Norm=CalcNormal(0.0f,-1.0f, 0.0f,-0.3f,-0.3f, 0.0f, 0.0f, 0.0f, 0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f); glTexCoord2f(0.75f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); Norm=CalcNormal(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-0.4f,-0.3f,-0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); glTexCoord2f(0.75f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f); Norm=CalcNormal(-1.0f, 0.0f, 0.0f,-0.3f, 0.3f, 0.0f, 0.0f, 0.0f,-0.4f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(1.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f); glTexCoord2f(0.75f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); Norm=CalcNormal(0.0f, 1.0f, 0.0f, 0.0f, 0.0f,-0.4f,-0.3f, 0.3f, 0.0f); glNormal3f(Norm.x,Norm.y,Norm.z); glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f); glTexCoord2f(0.75f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f); glEnd(); glEndList(); } // Calculate normal from vertices stVec CalcNormal(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) { double v1x,v1y,v1z,v2x,v2y,v2z; double nx,ny,nz; double vLen; stVec Result; // Calculate vectors v1x = x1 - x2; v1y = y1 - y2; v1z = z1 - z2; v2x = x2 - x3; v2y = y2 - y3; v2z = z2 - z3; // Get cross product of vectors nx = (v1y * v2z) - (v1z * v2y); ny = (v1z * v2x) - (v1x * v2z); nz = (v1x * v2y) - (v1y * v2x); // Normalise final vector vLen = sqrt( (nx * nx) + (ny * ny) + (nz * nz) ); Result.x = (float)(nx / vLen); Result.y = (float)(ny / vLen); Result.z = (float)(nz / vLen); return Result; } [edit] DownloadsGLTut7_(Display_Lists).zip - Zip containing Win32 and GLFW source code, texture images and a Win32 Binary. |



