Click here to Skip to main content
15,867,330 members
Articles / Database Development / SQL Server
Article

Decoding OpenGL Textures in Targa Format from an SQLite Database

Rate me:
Please Sign up or sign in to vote.
4.56/5 (3 votes)
29 Oct 2007Public Domain3 min read 45.7K   769   27   3
Framework for loading TGA image data from an SQLite table, decoding this data and binding it to OpenGL textures
Screenshot - minigl_2.jpg

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.

C++
void initGL()
{
/* Load texture from SQLite file and register
** its texture_id with OpenGL
*/    
    texture_id = load_texture(2); // test image stored at record #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:

C++
/* Texture_id was set in initGL()
*/    
    glBindTexture(GL_TEXTURE_2D, texture_id);

How the Code Works

A structure called b_pixels has been created to hold texture_ids, the actual texture data and information such as the height and the width of a particular texture:

C++
/* This structure holds the actual image data
** and some meta information about our textures
*/
typedef struct 
{
    byte* data;
    unsigned width;
    unsigned height;
    byte bytes_per_pixel;
    unsigned id;  //assigned by OpenGL
} 
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:

C++
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().

C++
/* This function converts a TGA image in uncompressed RGB format
** into a Windows Device Independent Bitmap (DIB).
**
** The TGA image data are in source; SQLite frees this memory,
** so we store our converted DIB image data into a newly allocated block.
**
*/
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}; 
    // uncompressed RGB only
    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;
            
                    // Actual TGA image may be larger due to extension blocks
                    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 )
                            {

                                    // swap red and blue
                                    temp = tga->data [i];
                                    tga->data[i] = tga->data[i+2];
                                    tga->data[i+2] = temp;
                            }
                        }
                        // else malloc() imgsize failed      
                    }
                    // else TGA file too small for image
                }
                // else TGA not 24 or 32 bit 
            }
            // else TGA invalid aspect
        }
       // else malloc() b_pixels failed
   }
   // else TGA header mismatch
   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.

Screenshot - minigl.jpg

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

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication


Written By
Software Developer
Germany Germany
I currently work as a self-employed language translator. Back in school, I learned what must have been VAX Basic - phosphor green code on a glass tube. After transitioning from a VAX terminal to a Sinclair ZX81, I eventually got an Apple IIe and taught myself 6502 machine language. The past 30-odd years since have seen projects in various languages, for example Paver, a project built around a DIY CPU called Sonne-16.

Comments and Discussions

 
QuestionHow do I Insert TGA in SqlLite Database ? Pin
sugar7229-Oct-07 23:54
sugar7229-Oct-07 23:54 
AnswerRe: How do I Insert TGA in SqlLite Database ? Pin
Michael Mangelsdorf30-Oct-07 6:36
Michael Mangelsdorf30-Oct-07 6:36 
GeneralRe: How do I Insert TGA in SqlLite Database ? Pin
sugar7230-Oct-07 22:00
sugar7230-Oct-07 22:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.