Introduction
I'm currently developing an OpenGL application based around a central SQLite database for common storage. One of the important things that any practical OpenGL application relies on is textures. This short project documents a solution for loading targa images stored in an SQLite database into textures OpenGL can use. A tiny sample application, plus a test database including an image, is provided.
Running/Building the Sample Application
The subfolder source contains the files minigl.c and tgatexture.c. The former is just a minimalist OpenGL application to demonstrate the functionality provided by the latter. A makefile for use with LCC-Win32 is also included. Minigl.exe needs the files sqlite3.dll (freeware) and test.s3db (which is the actual database containing the test image) to be present in the same folder.
Using the Code
(Disclaimer) First and foremost: this is a demo. Although I've tried to comment relevant sections, error checking is not adequate at all. Use it at your own risk. Low-level code can easily bluescreen your PC or even cause data loss due to unforeseen differences in graphics hardware. From a top-level perspective, all that's required for using our texture is to register it with OpenGL. This is done by calling load_texture()
with the row index of our image in the database table. OpenGL then provides us with an internal texture_id
that it uses to identify the texture in calls to OpenGL functions.
void initGL()
{
texture_id = load_texture(2);
That's it! Once this is done, we can use the texture_id
we were given by OpenGL to specify that texture for use in our OpenGL scene:
glBindTexture(GL_TEXTURE_2D, texture_id);
How the Code Works
A structure called b_pixels
has been created to hold texture_id
s, the actual texture data and information such as the height and the width of a particular texture:
typedef struct
{
byte* data;
unsigned width;
unsigned height;
byte bytes_per_pixel;
unsigned id; }
b_pixels;
Typically, you would set up an array of this type to hold your various textures. As it turns out, the call to load_texture()
described above obtains the texture_id
from OpenGL in exchange for the texture data and information contained in a temporary b_pixels
structure, named tga
in the source. The function load_texture()
internally fills this structure by means of the following invocation, where db
is an open SQLite3 handle, db_index
is the row ID of the texture data in the DB table and tga_filter
is a pointer to the function, listed below, which does the format conversion:
tga = (b_pixels*) blob_filter( db, db_index, tga_filter);
It should be possible to write other conversion filters, a png_filter()
function for instance, and pass them to blob_filter()
instead. The following is a listing of tga_filter()
.
void* tga_filter( const byte* source,
const unsigned long bytecount )
{
b_pixels* tga = NULL;
byte temp;
size_t imgsize;
byte tga_signature[12] = {0,0,2,0,0,0,0,0,0,0,0,0};
int tga_header_size = 18;
if (bytecount > tga_header_size && !memcmp(tga_signature, source, 12))
{
if (tga = malloc(sizeof(b_pixels)) )
{
tga->id = 0;
tga->width = source[13] * 256 + source[12];
tga->height = source[15] * 256 + source[14];
if (tga->width > 0 && tga->height > 0)
{
tga->bytes_per_pixel = source[16] / 8;
if ( tga->bytes_per_pixel == 3 || tga->bytes_per_pixel == 4 )
{
imgsize =
tga->bytes_per_pixel * tga->width * tga->height;
if ( imgsize + tga_header_size <= bytecount )
{
if ( tga->data = malloc ( imgsize ) )
{
memcpy ( tga->data, source + tga_header_size,
imgsize );
for ( unsigned long i=0;
i < imgsize;
i += tga->bytes_per_pixel )
{
temp = tga->data [i];
tga->data[i] = tga->data[i+2];
tga->data[i+2] = temp;
}
}
}
}
}
}
}
return (void*) tga;
}
As it's such a small project, I would like to encourage you to download and play with the source for more information.
Uploading Your Images into SQLite
The sample application comes with an SQLite database file containing a single test image in a table called b_binaries
. You would typically use an administration tool like SQLite Administrator for such tasks.
Conclusion
The project has shown an alternative to using individual files for storing OpenGL texture data. Having SQLite with its numerous wonderful attributes behind your OpenGL project could help with maintaining and scaling it.
Further Reading