65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (3投票s)

2007年10月29日

公共领域

3分钟阅读

viewsIcon

47044

downloadIcon

790

用于从 SQLite 表加载 TGA 图像数据,解码此数据并将其绑定到 OpenGL 纹理的框架

Screenshot - minigl_2.jpg

引言

我目前正在开发一个基于中央 SQLite 数据库的 OpenGL 应用程序,用于公共存储。任何实用的 OpenGL 应用程序所依赖的重要事项之一是纹理。这个简短的项目记录了一个解决方案,用于将存储在 SQLite 数据库中的 Targa 图像加载到 OpenGL 可以使用的纹理中。提供了一个小型示例应用程序,以及一个包含图像的测试数据库。

运行/构建示例应用程序

子文件夹source包含文件minigl.ctgatexture.c。前者只是一个极简的 OpenGL 应用程序,用于演示后者提供的功能。还包括一个用于 LCC-Win32 的 makefileMinigl.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 这样的管理工具来执行此类任务。

Screenshot - minigl.jpg

结论

该项目展示了使用单个文件存储 OpenGL 纹理数据的替代方案。 让 SQLite 凭借其众多的优秀属性支持您的 OpenGL 项目,可以帮助您维护和扩展它。

延伸阅读

© . All rights reserved.