从 SQLite 数据库解码 Targa 格式的 OpenGL 纹理






4.56/5 (3投票s)
用于从 SQLite 表加载 TGA 图像数据,解码此数据并将其绑定到 OpenGL 纹理的框架
 
 
引言
我目前正在开发一个基于中央 SQLite 数据库的 OpenGL 应用程序,用于公共存储。任何实用的 OpenGL 应用程序所依赖的重要事项之一是纹理。这个简短的项目记录了一个解决方案,用于将存储在 SQLite 数据库中的 Targa 图像加载到 OpenGL 可以使用的纹理中。提供了一个小型示例应用程序,以及一个包含图像的测试数据库。
运行/构建示例应用程序
子文件夹source包含文件minigl.c和tgatexture.c。前者只是一个极简的 OpenGL 应用程序,用于演示后者提供的功能。还包括一个用于 LCC-Win32 的 makefile。Minigl.exe需要文件sqlite3.dll(免费软件)和test.s3db(它是包含测试图像的实际数据库)存在于同一文件夹中。
Using the Code
(免责声明)首先,最重要的是:这是一个演示。虽然我试图注释相关部分,但错误检查根本不充分。 使用风险自负。 由于图形硬件中不可预见的差异,底层代码很容易导致您的 PC 蓝屏,甚至导致数据丢失。 从顶层来看,使用我们的纹理所需的全部就是将其注册到 OpenGL。 这是通过使用数据库表中图像的行索引调用load_texture()来完成的。 然后,OpenGL 为我们提供一个内部texture_id,它使用该 ID 来标识对 OpenGL 函数的调用中的纹理。
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
就是这样! 完成此操作后,我们可以使用 OpenGL 赋予我们的texture_id来指定该纹理以用于我们的 OpenGL 场景
/* Texture_id was set in initGL()
*/    
    glBindTexture(GL_TEXTURE_2D, texture_id);
代码工作原理
创建了一个名为b_pixels的结构来保存texture_id、实际纹理数据以及诸如特定纹理的高度和宽度之类的信息
/* 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;
通常,您会设置此类型的数组来保存您的各种纹理。 事实证明,上面描述的对load_texture()的调用会从 OpenGL 获取texture_id,以换取纹理数据和临时b_pixels结构中包含的信息,该结构在源代码中名为tga。 函数load_texture()通过以下调用在内部填充此结构,其中db是打开的 SQLite3 句柄,db_index是 DB 表中纹理数据的行 ID,tga_filter是指向以下列出的函数的指针,该函数执行格式转换
tga = (b_pixels*) blob_filter( db, db_index, tga_filter);
应该可以编写其他转换过滤器,例如png_filter()函数,并将它们传递给blob_filter()。 以下是tga_filter()的列表。
/* 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;
}
由于这是一个如此小的项目,我想鼓励您下载并使用源代码以获取更多信息。
将您的图像上传到 SQLite
该示例应用程序附带一个 SQLite 数据库文件,其中包含一个名为b_binaries的表中的单个测试图像。 通常,您会使用像 SQLite Administrator 这样的管理工具来执行此类任务。
 
 
结论
该项目展示了使用单个文件存储 OpenGL 纹理数据的替代方案。 让 SQLite 凭借其众多的优秀属性支持您的 OpenGL 项目,可以帮助您维护和扩展它。


