OUR SPHERE WORLD

To begin any C++ (or even just C) program, we need to include the headers that contain the function and class definitions that we will use in our program. The GLTools.h header contains the bulk of the GLTools C-like stand-alone functions, while the GLTools C++ classes each have their own header file.

#include <GLTools.h>

GLShaderManager.h brings in the GLTools shader manager class. You cannot render in OpenGL (core profile) without a shader. < br/> The shader manager not only allows you to build and manage your own shaders, it comes with a set of “stock shaders” that perform a few rudimentary and basic rendering operations.

#include 
#include //To construct our projection matrix

The GLTools library contains a simple container class called GBatch. This class can contain a single batch of any of the seven primitives, and it knows how to render the primitives when using any of the stock shaders supported by the GLShaderManager. Using the GLBatch class is simple. First initialize the batch, telling the class the type of primitive it represents, the number of vertices it will contain, and optionally, one or two sets of texture coordinates:

void GLBatch::Begin(GLenum primitive, GLuint nVerts, GLuint nTextureUnits = 0);

Then, at a minimum, copy in an array of three component (x, y, z) vertices.

void GLBatch::CopyVertexData3f(GLfloat *vVerts);

Optionally, you can also copy in surface normals, colors, and texture coordinates as well:

void GLBatch::CopyNormalDataf(GLfloat *vNorms); 
void GLBatch::CopyColorData4f(GLfloat *vColors); 
void GLBatch::CopyTexCoordData2f(GLfloat *vTexCoords, GLuint uiTextureLayer);

When you are finished, you can call End to signify you are done copying in data, and the internal flags will be set so the class knows which attributes it contains.

void GLBatch::End(void);

The GLBatch class, however, is simply a convenience class, much like using GLUT is convenient so you don’t have to worry about OS specifics until you are ready.

#include &lt;GLBatch.h&gt;
#include &lt;GLFrame.h&gt;
#include &lt;GLMatrixStack.h&gt;
#include &lt;GLGeometryTransform.h&gt;//To manage our matrix stacks.
#include &lt;StopWatch.h&gt;

#include &lt;math.h&gt;
#include &lt;stdio.h&gt;

GLUT gets a different treatment depending on whether you are building on a Mac. On Windows and Linux, we use the static library version of freeglut and thus need the FREEGLUT_STATIC preprocessor macro defined ahead of it.

Nothing can be rendered in the OpenGL core profile without a shader.As mentioned above.

GLShaderManager  shaderManager; // Shader Manager

Because matrix manipulation is such an important part of 3D graphics, almost every programmer’s toolbox contains a set of functions or classes for creating and manipulating them. In fact the math3d library contains a rich assortment of functions for this purpose. Transformations are often applied in a hierarchical manner, with one or more objects being drawn relative to one another. This would require a great deal of matrix construction and management by your client code to traverse a complex scene in 3D space. Traditionally, a matrix stack has been employed to facilitate this, and the GLTools library builds such as utility class on top of the math3d matrix functions. This class is called GLMatrixStack. Readers familiar with the now deprecated OpenGL matrix stacks in the compatibility profile will find this class familiar.The constructor of the class allows you to specify the maximum depth of the stack, with the default stack depth being 64. This matrix stack is also initialized to have the identity matrix already on the stack.

GLMatrixStack::GLMatrixStack(int iStackDepth = 64);

You can load the identity matrix on the top matrix by calling LoadIdentity.

void GLMatrixStack::LoadIdentity(void);

Or you can load an arbitrary matrix on top of the stack.

void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);

In addition you can multiply a matrix by the top of the matrix stack. The result of the multiplication is then stored at the top of the stack.

void GLMatrixStack::MultMatrix(const M3DMatrix44f);

Finally, getting the top value off the matrix stack is simply done with GetMatrix, which comes with two overloads suitable for use with the GLShaderManager or just getting a copy of top matrix.

const M3DMatrix44f&amp; GLMatrixStack::GetMatrix(void); 
void GLMatrixStack::GetMatrix(M3DMatrix44f mMatrix);

The GLMatrixStack class contains three overrides that even allow you to use the GLFrame class instead of a full matrix.

void GLMatrixStack::LoadMatrix(GLFrame&amp; frame); 
void GLMatrixStack::MultMatrix(GLFrame&amp; frame); 
void GLMatrixStack::PushMatrix(GLFrame&amp; frame);

The GLMatrixStack class also has built-in support for creating rotations, translating, and scaling matrices. The appropriate functions are listed here.

void MatrixStack::Rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); 
void MatrixStack::Translate(GLfloat x, GLfloat y, GLfloat z); 
void MatrixStack::Scale(GLfloat x, GLfloat y, GLfloat z);

These functions work similarly to their lower level math3d counterparts, with one exception. The Rotate function takes degrees instead of radians to more closely mimic the now deprecated OpenGL function glRotate. All three of these functions create the appropriate transformation matrix and then multiply it by the top of the matrix stack, essentially adding the transformation to the current matrix (remember you add transformations by multiplying the matrices). The real value of a matrix class is the ability to save the state by pushing it and then restoring the state later by popping it. With the GLMatrixStack class, you can save the current matrix value by pushing the matrix on the stack with the PushMatrix function. This actually copies the current matrix value and places the new value at the top of the stack. Likewise, PopMatrix removes the top matrix and restores the value underneath. There are several overloads for each of these:

Void GLMatrixStack::PushMatrix(void); 
void PushMatrix(const M3DMatrix44f mMatrix); 
void PushMatrix(GLFrame&amp; frame);
void GLMatrixStack::PopMatrix(void);

In addition to pushing the current matrix on the stack, you can also push an arbitrary matrix on the top of the stack via the M3DMatrix44f data type or the GLFrame class

GLMatrixStack    modelViewMatrix;
GLMatrixStack   projectionMatrix;

In an orthographic projection everything that falls within this space is displayed on-screen, and there is really no concept of a camera or eye coordinate system. To set this up, we call the GLFrustum method, SetOrthographic.

GLFrustum::SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, 
                           GLfloat zMin, GLfloat zMax);
GLFrustum      viewFrustum;//sets up the projection matrix for us.

You can probably guess that having a matrix stack for both the modelview matrix and the projection matrix carries a lot of advantages. Very often you will also need to retrieve both of these matrices and multiply them to get the modelview projection matrix. Another useful matrix is the normal matrix, which is used for lighting computations and is derived from the modelview matrix. Another utility class, GLGeometryTransform keeps track of these two matrix stacks for you and quickly retrieves the top of either matrix stack, the modelview projection matrix, or the normal matrix.

GLGeometryTransform       transformPipeline;// to manage our matrix stacks.

A simple GLTool wrapper class encapsulates our batch of triangles etc., and we declared an instance of this GLBatch class

GLTriangleBatch  torusBatch;
GLBatch     floorBatch;
GLTriangleBatch    sphereBatch;

A simple and flexible way to represent a frame of reference is to use a data structure (or class in C++) that contains a position in space, a vector that points forward, and a vector that points upward. Using these quantities, you can uniquely identify a given position and orientation in space. The class from the GLTools library, GLFrame, makes use of the math3d library and stores this information all in one place:GLFrame! Using a frame of reference such as this to represent an object’s position and orientation is a powerful mechanism. To begin with, you can use this data directly to create a 4 x 4 transformation matrix. The GLFrame class contains a function that retrieves an appropriately conditioned camera matrix:

void GetCameraMatrix(M3DMatrix44f m, bool bRotationOnly = false);
GLFrame   cameraFrame;
GLFrame   spheres[NUM_SPHERES];

void SetupRC();
void ChangeSize(int nWidth, int nHeight);
void RenderScene(void);
void SpecialKeys(int key, int x, int y);

!!!!!!!!This function does any needed initialization on the rendering context.!!! !!!!!!!!This is the first opportunity to do any OpenGL related tasks.!!!!!!!!!!!! !!!!!!!!This is where we do some one-time setup for our program.!!!!!!!!!!!!!!!!!

void SetupRC()
    {

The shader manager needs to compile and link its own shaders, though, so we must call the InitializeStockShaders method as part of our OpenGL initialization.

 // Initialze Shader Manager
  shaderManager.InitializeStockShaders();

Depth testing is another effective technique for hidden surface removal. The concept is simple: When a pixel is drawn, it is assigned a value (called the z value) that denotes its distance from the viewer’s perspective. Later, when another pixel needs to be drawn to that screen location, the new pixel’s z value is compared to that of the pixel that is already stored there. If the new pixel’s z value is higher, it is closer to the viewer and thus in front of the previous pixel, so the previous pixel is obscured by the new pixel. If the new pixel’s z value is lower, it must be behind the existing pixel and thus is not obscured. This maneuver is accomplished internally by a depth buffer with storage for a depth value for every pixel on the screen. You should request a depth buffer when you set up your OpenGL window with GLUT. For example, you can request a color and a depth buffer in main function like this:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);

If enabled, do depth comparisons and update the depth buffer. Note that even if the depth buffer exists and the depth mask is non-zero, the depth buffer is not updated if the depth test is disabled. See glDepthFunc and glDepthRange. If you do not have a depth buffer, then enabling depth testing will just be ignored.

glEnable(GL_DEPTH_TEST);

Polygons (triangles) don’t have to be solid. By default, polygons are drawn solid, but you can change this behavior by specifying that polygons are to be drawn as outlines or just points (only the vertices are plotted). The function glPolygonMode allows polygons to be rendered as filled solids, as outlines, or as points only. In addition, you can apply this rendering mode to both sides of the polygons or only to the front or back.

void glPolygonMode(GLenum face, GLenum mode);

Like in face culling, the face parameter can be GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK. The mode parameter can be GL_FILL (the default), GL_LINE, or GL_POINT.

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

This function sets the color used for clearing the window.The prototype for this function is

void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);

GLclampf is defined as a float under most implementations of OpenGL. Each parameter contains the weight of that color component in the final color desired. This function does not clear the background right away, but rather sets the color that will be used when the color buffer is cleared (possibly repeatedly) later.

/ Black background
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

A torus is a ring-shaped doughnut. The GLTools function to create a torus is gltMakeTorus.

void gltMakeTorus(GLTriangleBatch&amp; torusBatch, GLfloat majorRadius, 
                  GLfloat minorRadius, GLint numMajor, GLint numMinor);

The majorRadius is the radius from the center to the outer edge of the torus, while the minorRadius is the radius to the inner edge. The numMajor and numMinor parameters serve a similar purpose to the iSlices and iStacks parameters for spheres; they are the numbers of subdivisions along the major radius, and again along the inner minor radius.

 // This makes a torus
  gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);

A fundamental shape used for many “handmade” objects is the simple sphere. The gltMakeSphere function takes a reference to a triangle batch, the radius of the sphere, and the number of slices and stacks of which to compose the sphere.

void gltMakeSphere(GLTriangleBatch&amp; sphereBatch, GLfloat fRadius, 
                   GLint iSlices, GLint iStacks);

While the radius of the sphere should be fairly obvious, the iSlices and iStacks parameters warrant a little explanation. You can think of the sphere as a series of bands of triangles that go around the sphere. The iStacks parameter is the number of these bands stacked from the bottom of the sphere to the top. The iSlices parameter is the number of triangle pairs that stretch around the sphere. Typically the number of slices is twice the number of stacks for a nice symmetric sphere. Think about why—there are 360 degrees around a sphere, but only 180 (half that) from the top to the bottom. Another thing to note is these spheres are wrapped around the z-axis, thus +Z is at the top of the sphere, and –Z is at the bottom.

    // This make a sphere
    gltMakeSphere(sphereBatch, 0.1f, 26, 13);
GL_POINTS           Each vertex is a single point on the screen.
GL_LINES            Each pair of vertices defines a line segment. 
GL_LINE_STRIP       A line segment is drawn from the first vertex to each successive vertex. 
GL_LINE_LOOP        Same as GL_LINE_STRIP, but the last and first vertex are connected. 
GL_TRIANGLES        Every three vertices define a new triangle. 
GL_TRIANGLE_STRIP   Triangles share vertices along a strip. 
GL_TRIANGLE_FAN     Triangles fan out from an origin, sharing adjacent vertices.

The following code builds a batch of vertical and horizontal lines.

 floorBatch.Begin(GL_LINES, 324);
    for(GLfloat x = -20.0; x &lt;= 20.0f; x+= 0.5) {
        floorBatch.Vertex3f(x, -0.55f, 20.0f);
        floorBatch.Vertex3f(x, -0.55f, -20.0f);
        
        floorBatch.Vertex3f(20.0f, -0.55f, x);
        floorBatch.Vertex3f(-20.0f, -0.55f, x);
        }
    floorBatch.End();    

    // Randomly place the spheres
    for(int i = 0; i &lt; NUM_SPHERES; i++) {
        GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
        spheres[i].SetOrigin(x, 0.0f, z);
        }
}

Window has changed size, or has just been created. In either case, we need to use the window dimensions to set the viewport and the projection matrix.
The ChangeSize function receives the new width and height whenever the window size changes. We can use this information to modify the mapping of our desired coordinate system to real screen coordinates, with the help of the OpenGL function glViewport.
In the ChangeSize function, we set up our perspective projection. Because this is where we get notified of the window’s dimensions (or if they change), this is a reasonable place to put this code.

//Screen changes size or is initialized
void ChangeSize(int nWidth, int nHeight)
    {

The 1st and 2nd parameters specify the lower-left corner of the viewport within the window, and the width and height parameters specify these dimensions in pixels. Usually, x and y are both 0, but you can use viewports to render more than one drawing in different areas of a window. The viewport defines the area within the window in actual screen coordinates that OpenGL can use to draw in. The current clipping volume/coordinate system is then mapped to the new viewport. If you specify a viewport that is smaller than the window coordinates, the rendering is scaled smaller.

glViewport(0, 0, nWidth, nHeight);

The viewFrustum instance of the GLFrustum class sets up the projection matrix for us, and then we load that into our projection matrix object projectionMatrix.
A perspective projection performs perspective division to shorten and shrink objects that are farther away from the viewer. The width of the back of the viewing volume does not have the same measurements as the front of the viewing volume after being projected to the screen. Thus, an object of the same logical dimensions appears larger at the front of the viewing volume than if it were drawn at the back of the viewing volume. A frustum is a truncated section of a pyramid viewed from the narrow end to the broad end, with the viewer back some distance from the narrow end. The GLFrustum class constructs a frustum for you with the function SetPerspective.

GLFrustum::SetPerspective(float fFov, float fAspect, float fNear, float fFar);

The parameters are the field-of-view angle in the vertical direction, the aspect ratio of the width to the height of your window, and the distances to the near and far clipping planes. You find the aspect ratio by dividing the width (w) by the height (h) of the window or viewport.

// Create the projection matrix, and load it on the projection matrix stack
  viewFrustum.SetPerspective(35.0f, 
                                float(nWidth)/float(nHeight), 
                                1.0f, 
                                100.0f);
  projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

The last thing we do here is initialize the GLGeometryTransform instance transformPipeline by setting its internal pointers to our instances of the modelview matrix stack and projection matrix stacks. We really could have done this in the SetupRC function as well, but resetting them when the window changes size does no harm, and it keeps our matrix and pipeline setup all in one place.

    // Set the transformation pipeline to use the two matrix stacks 
  transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    }

GLUT by default updates the window by calling the RenderScene function when the window is created and when the window either changes size or is in need of being repainted. This happens anytime the window is minimized and restored, maximized,covered and redisplayed, and so on.

// Called to draw scene
void RenderScene(void)
  {

We set up arrays of floating-point numbers to represent the colors (with an alpha of 1.0), and pass these to a stock shader.

    // Color values
    static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
    static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    static GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };

Note how we made use of the CStopWatch class (a part of the GLTools library) to make our rotation rate based on the amount of time that has passed. Essentially we are rotating at a rate of 60 degrees per second. You should always base your animation rates on the passage of time, rather than a purely frame-based approach.For example, it is tempting to make animation code like this:

static GLfloat yRot = 0; 
yRot += 1.0f; 
m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);

Code like this rotates your object very slowly when the frame rate is low and very quickly when the frame rate is high, so the programmer tends to tweak the number added to yRot until the animation looks just right (Goldilocks programming!). However, the frame rate varies on different machines, different driver revisions, and so on, yielding unpredictable animation speeds on different machines. Time, however, flows constant, regardless of frame rate. A higher frame rate should yield a smoother animation, not a faster animation.

// Time Based animation
  static CStopWatch rotTimer;
  float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

The glClear function clears a particular buffer or combination of buffers. A buffer is a storage area for image information. The red, green, blue, and alpha components of a drawing are usually collectively referred to as the color buffer or pixel buffer.
More than one kind of buffer (color, depth, and stencil) is available in OpenGL, we use the bitwise OR operator to simultaneously clear all three of these buffers.All you really need to understand is that the color buffer is the place where the displayed image is stored internally and that clearing the buffer with glClear removes the last drawing from the window. You will also see the term framebuffer, which refers to all these buffers collectively given that they work in tandem.

 // Clear the color and depth buffers
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

The real value of a matrix class is the ability to save the state by pushing it and then restoring the state later by popping it. With the GLMatrixStack class, you can save the current matrix value by pushing the matrix on the stack with the PushMatrix function. This actually copies the current matrix value and places the new value at the top of the stack. Likewise, PopMatrix removes the top matrix and restores the value underneath. There are several overloads for each of these:

void GLMatrixStack::PushMatrix(void); 
void PushMatrix(const M3DMatrix44f mMatrix); 
void PushMatrix(GLFrame&amp; frame);
void GLMatrixStack::PopMatrix(void);

In addition to pushing the current matrix on the stack, you can also push an arbitrary matrix on the top of the stack via the M3DMatrix44f data type or the GLFrame class. Next, in the RenderScene function, we begin rendering our geometry by first saving the modelview matrix, which has been set to the identity matrix by default.

    // Save the current modelview matrix (the identity matrix)
  modelViewMatrix.PushMatrix();

There is really no such thing as a camera transformation in OpenGL. We use the camera as a useful metaphor to help us manage our point of view in some sort of immersive 3D environment. If we envision a camera as an object that has some position in space and some given orientation, we find that our current frame of reference system can represent both actors and our camera in a 3D environment. To apply a camera transformation, we take the camera’s actor transform and flip it so that moving the camera backward is equivalent to moving the whole world forward. Similarly, turning to the left is equivalent to rotating the whole world to the right. The GLFrame class contains a function that retrieves an appropriately conditioned camera matrix:

void GetCameraMatrix(M3DMatrix44f m, bool bRotationOnly = false);

Here we added the flexibility that you can get the camera’s rotation transform only. The C++ default parameter here allows you to ignore this unless you have some special need for this feature. For example, a frequently employed technique for immersive environ- ments is the sky box. A sky box is simply a big box with a picture of the sky on it. You and your immediate surroundings are rendered inside this box. As you move around, the sky and background should move (rotate only) as well, but you do not want to be able to walk up to the edge of the sky. You would simply apply only the rotation component of the camera transform to your sky box, while everything else in the world would be trans- formed by the full camera transform.
Let’s add a camera to SphereWorld so you can get a better idea of how this works in General,which contains the ability to move around via the arrow keys.

    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.PushMatrix(mCamera);

IF WE WANT TO MAKE TORUS AND OTHER OBJECTS SOLID, WE HAVE TO DEFINE LIGHT AS SHOWN BELOW.

// Transform the light position into eye coordinates
    M3DVector4f vLightPos = { 0.0f, 10.0f, 5.0f, 1.0f };
    M3DVector4f vLightEyePos;
    m3dTransformVector4(vLightEyePos, vLightPos, mCamera);

To render geometry, you need to submit the attribute arrays for your object, but first you must bind to the shader program you want to use and supply the program’s uniforms. The GLShaderManager class takes care of this for you (for now). The function UseStockShader selects one of the stock shaders and supplies the uniforms for that shader, all in one func- tion call.

GLT_SHADER_IDENTITY: This shader does nothing but render geometry on-screen in the default Cartesian coordinate system(-1.0 to 1.0 on all axes), using the color specified. The only attribute used is GLT_ATTRIBUTE_VERTEX. The vColor parameter contains the desired color.

GLShaderManager::UseStockShader(GLT_SHADER_IDENTITY, GLfloat vColor[4]);

GLT_SHADER_FLAT: This shader extends the identity shader by allowing a 4 x 4 transformation matrix to be specified for geometry transformations. This is typically the premultiplied modelview matrix and the projection matrix, often called the modelview projection matrix,only attribute used is GLT_ATTRIBUTE_VERTEX.

GLShaderManager::UseStockShader(GLT_SHADER_FLAT, GLfloat mvp[16], GLfloat vColor[4]);

GLT_SHADER_SHADED: This shader’s only uniform is the transformation matrix that is to be applied to the geometry. Both the GLT_ATTRIBUTE_VERTEX and the GLT_ATTRIBUTE_COLOR are used by the shader. Color values are interpolated smoothly between vertices (smooth shading this is Called).

GLShaderManager::UseStockShader(GLT_SHADER_SHADED, GLfloat mvp[16]);

GLT_SHADER_DEFAULT_LIGHT: This shader creates the illusion of a single diffuse light source located at the eye position. Essentially, it makes things look shaded and lit. Uniforms needed are the modelview matrix, the projection matrix, and the color value to use as the base color. Required attributes are GLT_ATTRIBUTE_VERTEX and GLT_ATTRIBUTE_NORMAL. Most lighting shaders require the normal matrix as a uniform. This shader derives the normal matrix from the modelview matrix—convenient, but not terribly efficient. Bear that in mind for performance-sensitive applications.

GLShaderManager::UseStockShader(GLT_SHADER_DEFAULT_LIGHT, GLfloat mvMatrix[16], 
                                GLfloat pMatrix[16], GLfloat vColor[4]);

GLT_SHADER_POINT_LIGHT_DIFF: The point light shader is similar to the default light shader, but the light position may be specified. This shader takes four uniforms, the modelview matrix, the projection matrix, the light position in eye coordinates, and the base diffuse color of the object. Attributes used are GLT_ATTRIBUTE_VERTEX and GLT_ATTRIBUTE_NORMAL.;

GLShaderManager::UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, GLfloat mvMatrix[16], 
                                GLfloat pMatrix[16], GLfloat vLightPos[3], GLfloat vColor[4])

GLT_SHADER_TEXTURE_REPLACE: This shader transforms geometry by the given modelview projection matrix and uses the texture bound to the texture unit specified in nTextureUnit. Fragment colors are taken directly from the texture sample. Attributes used are GLT_ATTRIBUTE_VERTEX and GLT_ATTRIBUTE_TEXTURE0.;

GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_REPLACE, GLfloat mvpMatrix[16], GLint nTextureUnit)

GLT_SHADER_TEXTURE_MODULATE: This shader multiplies a base color by a texture from texture unit nTextureUnit. Attributes used are GLT_ATTRIBUTE_VERTEX and GLT_ATTRIBUTE_TEXTURE0.

GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_MODULATE, GLfloat mvpMatrix[16], 
GLfloat vColor, GLint nTextureUnit);

GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF: This shader modulates (multiplies) a texture by a diffuse lighting calculation, given a light’s position in eye space. Uniforms are the modelview matrix, projection matrix, the light position in eye space, the base color of the geometry, and the texture unit to use. Attributes used are GLT_ATTRIBUTE_VERTEX, GLT_ATTRIBUTE_NORMAL, and GLT_ATTRIBUTE_TEXTURE0

GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF, GLfloat mvMatrix,
        GLfloat pMatrix[16], GLfloat vLightPos[3], GLfloat vBaseColor[4], GLint nTextureUnit);

After giving all necessary info, lets continue to our code….

// Draw the ground
  shaderManager.UseStockShader(GLT_SHADER_FLAT,                             transformPipeline.GetModelViewProjectionMatrix(),
            vFloorColor); 
  floorBatch.Draw();    
    
    for(int i = 0; i &lt; NUM_SPHERES; i++) {
        modelViewMatrix.PushMatrix();

In addition you can multiply a matrix by the top of the matrix stack. The result of the multiplication is then stored at the top of the stack.

void GLMatrixStack::MultMatrix(const M3DMatrix44f);
modelViewMatrix.MultMatrix(spheres[i]);

IF WE WANT TO DRAW SOLID OBJECTS WE USE THE CODE BELOW.

shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, 
                             transformPipeline.GetModelViewMatrix(), 
                             transformPipeline.GetProjectionMatrix(), 
                             vLightEyePos, vSphereColor);
        shaderManager.UseStockShader(GLT_SHADER_FLAT, 
                             transformPipeline.GetModelViewProjectionMatrix(),
                             vSphereColor);
        sphereBatch.Draw();
        modelViewMatrix.PopMatrix();
        }

This may seem pointless given that the next thing we do is draw the ground, which doesn’t get transformed at all. It is good practice to save your matrix state at the beginning of your rendering pass and then restore it at the end with a corresponding PopMatrix. This way you do not have to reload the identity matrix every time you render, plus for organizational purposes it’s going to come in handy very soon when we add the camera.Now, finally the code to move our torus into place. We begin by calling Translate to apply a translation matrix to the top of the matrix stack. This moves the torus back away from the origin (where we are) so that we can see it. This is followed by a rotation with Rotate. The parameters to Rotate rotate the torus around the y-axis, and yRot is derived from the amount of time that has passed since the last frame.

    // Draw the spinning Torus
    modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
    
    // Save the Translation
    modelViewMatrix.PushMatrix();
        
// Apply a rotation and draw the torus
    modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);

A SOLID WORLD AGAIN!

shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, 
                             transformPipeline.GetModelViewMatrix(), 
                             transformPipeline.GetProjectionMatrix(),
                             vLightEyePos, vTorusColor);
    shaderManager.UseStockShader(GLT_SHADER_FLAT, 
                             transformPipeline.GetModelViewProjectionMatrix(),
                             vTorusColor);
    torusBatch.Draw();

The final matrix is then passed to the shader as a uniform, and the torus batch is submit- ted to render the object. Rather than getting the current modelview matrix and the projec- tion matrix and then multiplying them, we can now simply ask the transformPipeline for the concatenated matrix. This makes our code much cleaner, less cluttered, and easier to read. This transformation matrix is still at the top of our stack, so we remove it, restor- ing identity by calling PopMatrix.

    modelViewMatrix.PopMatrix(); // "Erase" the Rotation from before

    // Apply another rotation, followed by a translation, then draw the sphere
    modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
    modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, 
                             transformPipeline.GetModelViewMatrix(), 
                             transformPipeline.GetProjectionMatrix(), 
                             vLightEyePos, vSphereColor);
    shaderManager.UseStockShader(GLT_SHADER_FLAT,
                             transformPipeline.GetModelViewProjectionMatrix(),
                             vSphereColor);
    sphereBatch.Draw();

  // Restore the previous modleview matrix (the identity matrix)
     modelViewMatrix.PopMatrix();
     modelViewMatrix.PopMatrix();

The GLBatch method Draw simply submits the geometry to the shader and ta-da!—red triangle…well, almost. There is one last detail. When we set up our OpenGL window, we specified that we wanted a double buffered rendering context. This means rendering occurs on a back buffer and then is swapped to the front when we are done. This prevents the viewer from seeing the scene being rendered, along with a likely flickering between animation frames. Buffer swaps are done in a platform-specific manner, but GLUT has a single function call that does this for you:

 // Perform the buffer swap to display back buffer
      glutSwapBuffers();

Calling glutPostRedisplay yourself is a way in which you can let GLUT know that something has changed and it’s time to rerender the scene.

    // Tell GLUT to do it again
    glutPostRedisplay();
    }

It receives a keycode for the key being pressed, and also the x and y location (in pixels) of the mouse cursor in case that is also useful.

/ Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
    {
  float linear = 0.1f;
  float angular = float(m3dDegToRad(5.0f));
  
  if(key == GLUT_KEY_UP)
    cameraFrame.MoveForward(linear);
  
  if(key == GLUT_KEY_DOWN)
    cameraFrame.MoveForward(-linear);
  
  if(key == GLUT_KEY_LEFT)
    cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
  
  if(key == GLUT_KEY_RIGHT)
    cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);    
    }

Console-mode C and C++ programs always start execution with the function main. If you’re an experienced Windows nerd, you might wonder where WinMain is in this example. It’s not there because we start with a console-mode application, so we don’t have to start with window creation and a message loop. With Win32, you can create graphical windows from console applications, just as you can create console windows from GUI applications. These details are buried within the GLUT library. (Remember, the GLUT library is designed to hide just these kinds of platform details.)

// Main entry point for GLUT based programs
int main(int argc, char* argv[])
    {

The GLTools function gltSetWorkingDirectory sets the current working directory. This is actually not necessary on Windows, as the working directory is by default the same direc- tory as the program executable. On Mac OS X, however, this function changes the current working folder to be the /Resources folder inside the application bundle. A GLUT prefer- ences setting does this automatically, but this method is safer and always works, even if that setting is changed by another program. This comes in handy later when we want to load texture files or model data.

gltSetWorkingDirectory(argv[0]);

Next, we do some standard GLUT-based setup. The first order of business is a call to glutInit, which simply passes along the command-line parameters and initializes the GLUT library.

glutInit(&amp;argc, argv);

Next, we must tell the GLUT library what type of display mode to use when creating the window: The flags here tell it to use a double-buffered window (GLUT_DOUBLE) and to use RGBA color mode (GLUT_RGBA). A double-buffered window means the drawing commands are actually executed on an off-screen buffer and then quickly swapped into view on the window later. This method is often used to produce animation effects and is demonstrated later in this chapter. The GLUT_DEPTH bit flag allocates a depth buffer as part of our display so we can perform depth testing, and likewise GLUT_STENCIL makes sure we also have a stencil buffer available.

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

Next, we tell GLUT how big to make the window and to go ahead and create the window, with a caption that reads, “OpenGL SphereWorld”:

    glutInitWindowSize(800,600);
    glutCreateWindow("OpenGL SphereWorld");

GLUT supports another callback function, called glutSpecialFunc. This function registers a function that is called whenever a special key is pressed. In GLUT parlance, this is one of the function keys or one of the directional keys (arrow keys, page up/down, and so on). The following line is added to our main function to register the SpecialKeys callback function for this purpose.

glutSpecialFunc(SpecialKeys);

Internally GLUT runs a system native message loop, intercepts the appropriate messages, and then calls callback functions you register for different events. This is somewhat limited compared to using a real system-specific framework, but it greatly simplifies getting a program up and running, and the minimal events are supported for a demo framework. Here, we must set a callback function for when the window changes size so that we can set up the viewport, and we register a function that will contain our OpenGL rendering code.

    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);

Before we start the main message loop running, there are still two things we need to take care of. The first is to initialize the GLEW library. Recall the GLEW library initializes all the missing entry points in our OpenGL driver to make sure we have the full OpenGL API available to us. A call to glewInit does the trick, and we check to make sure nothing goes wrong with the driver initialization before we try and do any rendering.

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
        }

The final piece of preparation is the call SetupRC. This function has nothing to do with GLUT actually but is a convenient place to do any OpenGL initialization we need performed before the actual rendering begins. The RC stands for rendering context, which is the logical handle to a running OpenGL state machine. A rendering context must be created before any OpenGL function will work, and GLUT sets this up for us when we first create the window.

SetupRC();

Finally, it’s time to start the main program loop and end the main function. The glutMainLoop function never returns after it is called until the main window is closed and needs to be called only once from an application. This function processes all the oper- ating system-specific messages, keystrokes, and so on until you terminate the program. It also makes sure those callback functions we registered earlier are called appropriately.

    glutMainLoop();    
    return 0;
    }

Another way to improve rendering performance is to update only the portion of the screen that has changed. You may also need to restrict OpenGL rendering to a smaller rectangular region inside the window. OpenGL allows you to specify a scissor rectanglewithin your window where rendering can take place. By default, the scissor rectangle is the size of the window, and no scissor test takes place. You turn on the scissor test with the ubiquitous glEnable function:

glEnable(GL_SCISSOR_TEST);

You can, of course, turn of f the scissor test again wi th the corresponding glDisable function call. The rectangle within the window where rendering is performed, called the scissor box, is specified in window coordinates (pixels) with the following function:

void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);

The x and y parameters specify the lower-left corner of the scissor box, with width and height being the corresponding dimensions of the scissor box.

Reklamlar

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Connecting to %s