31st of Dec. 2007 by Michael

Desktop Projects

Displaying/Storing OpenGL Textures in SQLite using C

I’ve created this project around 2007.

There is a tiny sqlite3 file test.s3db that the program reads, and in which you can store texture files in Targa (.tga) format.

This can be done using DB Browser for SQLite or any other similar tool. Targa was chosen because I could roll my own without a library to parse it.

 
 
 
 

The C program compiles on Windows and displays the texture in an OpenGL window. minigl.c is just a wrapper that displays on OpenGL window. tgatexture.c contains the main functionality of loading text texture, decoding Targa etc.

/* TGATexture - contains functions to load OpenGL textures
** in Targa format from an SQLight database file.
** 
** Build Environment: LCC-Win32. Use at your own risk.
**
** Bugs in low-level programs such as this may bluescreen
** your PC, possibly causing data loss.
**
** 2007 Michael <mim@ok-schalter.de>
*/

#include <GL/glaux.h>

#include <stdio.h>
#include <sqlite3/sqlite3.h>



typedef unsigned char byte;

/* 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;



int load_texture( int db_index );

void* blob_filter( const sqlite3*, const unsigned long, void* (*func)(byte*, unsigned long) );

void* tga_filter( const byte*, const unsigned long );



/* Load texture from SQLite file and register
** its texture_id with OpenGL
*/
int load_texture( int db_index )
{
    b_pixels* tga;  // pointer to Device Independent Bitmap (DIB),
                    // converted from targa format
    sqlite3* db;
    GLuint type;
    int r=0;        // resource_id, on error return 0
        
    sqlite3_open("test.s3db", &db); 
  if ( sqlite3_errcode(db) == SQLITE_OK )
    {

/* The following line is the center of this little project.
** Blob_filter() retrieves the image data from the db and
** executes tga_filter() as a call back function,
** which decodes the TGA image data into a Windows DIB and
** returns a pointer to the DIB data back to Blobfilter(),
** which simply returns this pointer to the caller.
*/  
        if ( tga = (b_pixels*) blob_filter( db, db_index, tga_filter) )
      {      
         type = (tga->bytes_per_pixel) == 4 ?  GL_RGBA : GL_RGB;
                     
         glGenTextures(1, &tga->id);         
         
         glBindTexture(GL_TEXTURE_2D, tga->id);
         glTexImage2D( GL_TEXTURE_2D, 0, type, tga->width,
                       tga->height, 0, type, GL_UNSIGNED_BYTE,
                       tga->data );
         
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
         
         glTexImage2D(GL_TEXTURE_2D, 0, type, tga->width, tga->height, 0, type, GL_UNSIGNED_BYTE, tga->data);
     
       r=tga->id; 

         free (tga->data);
         free (tga);
      }
    }  
    sqlite3_close( db );
    return r;
}



/* Blob_filter() interfaces with SQLite to actually retrieve 
** the image data from a binary large object (BLOb) field.
** 
** The conversion part is done by a filter function, to which
** the caller passes a pointer in parameter func.
**
** This callback mechanism serves to isolate the image conversion
** stuff in tga_filter() from the SQLite stuff.
*/
void* blob_filter( const sqlite3*       db,
                   const unsigned long  key_id,
                   void* (*func)(byte*, unsigned long) )
{            
  const char *sql = "SELECT b_data, b_byte_count FROM b_binaries WHERE b_id = ?1";
  sqlite3_stmt *stmt;
  int rc;
  void* ptr = NULL;

  rc = sqlite3_prepare(db, sql, -1, &stmt, 0);
  if( rc == SQLITE_OK )
  {
    sqlite3_bind_int(stmt, 1, key_id);
    rc = sqlite3_step(stmt);

    if (rc == SQLITE_ROW)
    {           
        ptr = func( (byte*) sqlite3_column_blob(stmt, 0),
                    sqlite3_column_int(stmt, 1) );
    
      rc = sqlite3_finalize(stmt);
    }
  }  
  return ptr;
}



/* 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;
}

Downloads

Package download