从 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 项目,可以帮助您维护和扩展它。