Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

Simple OpenGL Test Framework

4.95/5 (14 votes)
4 Mar 2009CPOL5 min read 106.8K   6.6K  
A simple OpenGL framework for fast prototyping of OpenGL and game applications
GLDemoApp

Introduction

This is a simple framework for prototyping OpenGL and game applications. It provides a quick way to get up and running with all of the most commonly used tools already built in.

Included in the framework are the following features:

  • Collada Loader
  • OpenGL Renderer
  • FreeType Font Rendering
  • TGA Texture Loading
  • Frame-rate Counting
  • Full-screen/Windowed Support

Included inside of the zip file are the following compiled third party libraries.

  • Collada DOM
  • GLEW
  • FreeType

Using the Code

In order to use the framework, simply unzip GLDemoApp_demo.zip. Open up the project with Visual Studio 2005. There are known issues when working with Visual Studio 2008, you will need to rebuild the Collada DOM libraries with Visual Studio 2008.

Before using the framework, please take a moment to observe the directory structure. At the top level, there should be three directories:

  • "3rdParty" - Contains all of the third party library and header files used in the framework
  • "bin" - This is where all the executable files go after building the solutions; inside of this directory are these sub-directories: release and resources
  • "GLDemoApp" - This is where all of the source files and *.sln files are contained

The main point of interest in the code is contained inside of demo.cpp. Inside this file, there are three functions:

C++
void InitDemo()
{
    RenderInit();
    CColladaLoader loader;
    g_pTestColladaMesh = loader.LoadColladaFile(BuildResourcePath("test.dae"));
    g_uiTextureId = RenderLoadTexture(BuildResourcePath("test.tga"));
}

bool RunDemo()
{
    static float32 fRotation = 0.0f;
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();

    gluLookAt(0.0f, 0.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
    
    RenderGroundGrid(-4.0f);
    
    glPushMatrix();
        glRotatef(fRotation, 1.0f, 1.0f, 1.0f);
        RenderMesh(*g_pTestColladaMesh);
    glPopMatrix();

    glPushMatrix();
    glPointSize(10.0f);
    glBegin(GL_POINTS);
    glColor3f(1.0f, 1.0f, 1.0f);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glEnd();
    glPopMatrix();

    glPopMatrix();
    
    RenderText(&g_defaultFont, "F1 : Fullscreen", Vector2f(0.0f, 20.0f));
    RenderText(&g_defaultFont, "F2 : Windowed", Vector2f(0.0f, 40.0f));


    RenderBegin2dMode();
        
    RenderTexture(Vector2f(RenderGetOrthoWidth() * .5f, 50.0f), g_uiTextureId, 0.0f);

    RenderEnd2dMode();

    if(GetAsyncKeyState(VK_F1))
    {
        sRenderResolution sRes;
        sRes.nWidth = RenderGetDesiredWidth();
        sRes.nHeight = RenderGetDesiredHeight();
        sRes.nBitDepth = RenderGetBitDepth();

        RenderSetResolution(sRes, true);
    }else if(GetAsyncKeyState(VK_F2))
    {
        sRenderResolution sRes;
        sRes.nWidth = RenderGetDesiredWidth();
        sRes.nHeight = RenderGetDesiredHeight();
        sRes.nBitDepth = RenderGetBitDepth();

        RenderSetResolution(sRes, false);
    }

    fRotation += .1f;
    if(fRotation > 360.0f)
        fRotation = 0.0f;

    RenderStats();
    RenderSwapBuffers();

    return (GetAsyncKeyState(VK_ESCAPE) & 0xFFFF) ? false : true;
}

void EndDemo()
{
    RenderReleaseTexture(g_uiTextureId);
    RenderReleaseMesh(&g_pTestColladaMesh);
    RenderDestroy();
}

It's pretty easy to see what is going on in here. InitDemo() is called from gldemoapp.cpp inside the winmain function right before the main app loop is entered. Inside the InitDemo() function, you should add any initialization code that you need for your application. Keep in mind that this function is only called once during the lifetime of the application. By default, inside the InitDemo() function, there is some code that loads a Collada file, and a texture file. You can simply remove most of this code except for RenderInit(), which does all of the OpenGL initialization stuff. The BuildResourcePath() function builds a path relative to the current directory from which the app is being run, one directory up and inside a folder named "resources". Look over the directory structure, and you will see that BuildResourcePath() always supplies a path that is "ACTUALPATH\\bin\\resources\\yourfilename.ext".

Next is the RunDemo() function. Inside it, you should put the bulk of your code. This function is called repeatedly during the execution of the application. It is important to note that this function returns a bool. This indicates whether the application should continue to run, or exit immediately. As you can see, there are several draw calls already inside this function. These are here simply for demonstration, and can be safely removed. Although, you should keep glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) and RenderSwapBuffers().

Finally, the EndDemo() function is called when the application is about to terminate its execution. This is where most clean up code should be placed.

Rendering Functions

The framework provides many utilities that should make using OpenGL a lot easier. Some of the rendering and utility functions which you may find useful are listed here:

  • C++
    RenderLoadTexture(const std::string& strFilePath)

    Loads a TGA texture from disk and returns the OpenGL texture object ID. This ID can be used in calls to glBindTexture.

  • C++
    RenderGroundGrid(float32 fYPos)

    This function draws a grid on the ground at the given Y-coordinate position.

  • C++
    RenderText(CFTFont* pFont, const char* strText, Vector2f& vtPosition, float32 fScale, const sRGBColor& rgbColor)

    This function displays text using the font provided as the first parameter. By default, inside RenderInit(), there is a font loaded, and it can be accessed by using the global variable g_defaultFont. For example, if you want to display some text, you could do the following...

    C++
    RenderText(&g_defaultFont, "Your cool text here", Vector2f(0.0f, 20.0f));
  • C++
    RenderQueryResolutions(std::list<srenderresolution />& lstResolution)

    Retrieves a list of available resolutions on the current display.

  • C++
    RenderSetResolution(sRenderResolution& rRes, bool bFullScreen)

    Sets the current resolution for the OpenGL window. Additionally, it can switch to full-screen by passing "true" in the second parameter. For example, to set the resolution and switch to full-screen, you could do the following...

    C++
    sRenderResolution rRes;
    rRes.nWidth = 640;
    rRes.nHeight = 480;
    rRes.nBitDepth = 32;
    RenderSetResolution(rRes, true);
  • C++
    RenderBegin2dMode()

    Using this function will switch the current projection matrix to be orthographic. It is important to note that the orthographic resolution is independent of the perspective resolution.

  • C++
    RenderEnd2dMode()

    Use this function when you are done drawing in orthographic mode. The following snippet would draw a loaded texture at 50,50:

    C++
    RenderBegin2dMode();
    RenderTexture(50.0f, 50.0f), g_uiTextureId, 0.0f);
    RenderEnd2dMode();
  • C++
    std::string ReadTextFileToBuffer(const std::string& strFileName)

    This function will load a file from disk and put its contents in the returned buffer. This is useful for loading shaders.

Utility Classes

In addition to the above functions, there are several classes which you will find useful when working with the framework:

  • CFTFont- This class is a wrapper for the FreeType library. It will load a given FreeType font and create the proper display lists for rendering. You can use an instance of this class as a parameter for RenderText.
  • C++
    CFTFont coolFont;
    coolFont.Init(BuildResourcePath("MyAwesomeFont.TTF"), 18);
    RenderText(&coolFont, "Loaded the font!", Vector2f(0.0f, 20.0f));
  • CColladaLoader- This is a wrapper class for the Collada DOM library. This will load a Collada mesh file and store its constants into an instance of sMesh. Once the file has been loaded and processed, the instance returned from the load function can be used in calls to void RenderMesh(const sMesh& pMesh). The loader will load textures as long as they are TGA format. Please keep in mind that a lot of extra data provided by Collada will be discarded once it is loaded.
  • C++
    CColladaLoader loader;
    sMesh* pMyMesh = loader.LoadColladaFile(BuildResourcePath("colladaTest.dae"));
    
    RenderMesh(*pMyMesh);
    
    //Once you are done with the mesh call
    //
    RenderReleaseMesh(&pMyMesh);

Additional Notes

Feel free to look around in the source files provided. There are many helper functions at your disposal that should make your life easier. If you run into any issues running a compiled executable, be sure to double check what your "Working Directory" is set to (should be "..\bin\debug" for debug builds and "..\bin\release" for release builds). This option can be found under "Debugging" in the Solution Properties window.

If you have any questions or comments about the code, please feel free to contact me at rebelcoder at gmail.com.

History

  • 4th March, 2009: Initial post
  • 4th March, 2009: Changes made to article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)