Working with textures in OpenGL meant until very recently working with images with sizes of power of two, limited to 1024, 2048 or 4096. On April 26, 2005, Mark J. Kilgard published the NVIDIA OpenGL 2.0 Support notes
, making direct reference to the fact that "NVIDIA’s GeForce 6 Series and NV4xGL-based Quadro FX GPUs fully support non-power-of-two textures at the fragment level" (of course, with some limitations). From a programmer's point of view, it may be sometimes attractive to work with images of whatever size (and I mean pretty large images) and think of them implicitly as non-power-of-two large textures, let's say of a 8000 x 3000 pixel size, and not to care a bit about the well known texture "kitchen".
anyTex is a class allowing you to load a bitmap of a given color depth from a file and think of it as texture with no restrictions (of course, limited by the computer resources, that is something we have to live with).
Working with the class
anyTex comes with two files, anytex.cpp and anytex.h, which you have to add to your project. Make sure you have OpenGL32.lib, GLu32.lib, GLaux.lib in the Link tab of your project settings. Then
#include "anytex.h" in the header file of your main dialog class. Add a public member of type
AnyTex to the main dialog class:
CStatic control to your application, which will be responsible for rendering your OpenGL scenes (I made that choice just for the sake of the presentation). Then, add a
CStatic derived class with the wizard and map a variable of that type to the control. Let us assume that
m_oglDisplay is the name of that variable. In the
OnInitDialog() function, create the OpenGL rendering context by passing the address of the control to the
InitializeOpenGL() function provided by the
if ( !m_atImage.InitializeOpenGL(&m_oglDisplay) )
AfxMessageBox("Cannot initialize OpenGL");
Before going further, keep in mind that, behind the scene,
anyTex still works with power-of-two classical textures as basic square cells. By default, the cell size is 1024. Should you want to set another cell size, you are free to do it by calling the
SetTexCellSize(int nSize) function provided by
anyTex. You may choose whatever value you want for
anyTex adjusts it automatically to 128, 256, 512 or 1024. Load a bitmap image of your choice and create the
anyTex texture, which will be called further on just
anyTex for simplicity.
if ( m_atImage.LoadBmpImage("test.bmp") ) m_atImage.CreateTex();
CreateTex() function needs a boolean parameter, which by default is
false, this leading to creation of 2D image textures. By calling the function with the parameter set to
true, mipmaps are generated. From now on, you have only to call the
PreRender() function (which can be overwritten according to your needs) and the
Render() function of the
anyTex class from within the
OnPaint() function of your
CStatic derived class.
The things behind
anyTex is supported by a
CList <UINT, UINT> m_listTex, storing the ID of the texture cells. The bitmap is brought into the memory as a DIB.
anytex "goes" throughout the DIB, sequentially extracting squares with the same size as the basic texture cell. Each square is blitted to a memory device context, resulting a DDB. The DDB is converted to a DIB having a 32 color depth, which is used then to generate a basic texture cell or its corresponding mipmaps, according to the boolean parameter passed to the
AnyText::CreateTex() function. The texture ID is added to
anyTex considers a square texture canvas of size 1 mapped over the
anyTex object in the following way:
anyTex is top-left aligned to the canvas. The
AnyTex::Render() function renders
anyText as it is, as a whole. Should you now be interested in 3D rendering and need to use the component texture cells individually, all you have to do is to call the:
UINT AnyTex::RetrieveTexCell(double atX, double atY,
double &renLeft, double &renTop, double &renSize)
function and pass the
atX, atY position on the logical canvas as parameters. The function returns the texture ID for the corresponding cell or 0 in case no one is found. A non-zero ID means a valid ID, and the basic cell pointed by that ID is rendered at
renLeft, renTop and has the size stored in
renSize, values which can be used further in your computations.