我最近一直在用纯 C 语言研究一点位图解析器,只是为了了解更简单图像格式的低级工作原理。到目前为止,使用维基百科关于位图文件的文章,我已经能够(至少我认为)正确解析信息 - 至少大部分是这样。
问题是我不太确定从那里做什么:因为我一直在使用 3.1 上下文,所以我可以访问更多现代化的功能,这很好,尽管我仍然迷路了。我有一个带有 GLFW 的窗口设置,到目前为止还没有真正呈现任何东西,因为我一直专注于解析/低级细节。
由于我非常努力地避免查看实际的代码示例,如果有人可以向我解释渲染位图所涉及的过程是什么,只使用 OpenGL/GLFW 和 ISO C 标准库,那就太棒了。
虽然我有几个着色器,并且我能够毫无问题地加载它们,但我认为我需要做的是渲染一个符合尺寸(宽度,高度)的[不可见]四边形图像本身,然后将像素数据传递给 OpenGL。然而,主要问题是着色器的设置如下:
顶点着色器
#version 150
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec2 Position;
layout(location = 1) in vec2 UV_In;
out vec2 UV;
void main()
{
gl_Position = vec4( Position, 0.0f, 1.0f );
UV = UV_In;
}
片段着色器
#version 150
#extension GL_ARB_separate_shader_objects : enable
in vec2 UV;
out vec3 Output;
uniform sampler2D TheSampler;
void main()
{
Output = texture2D( TheSampler, UV ).rgb;
}
而且我不确定如何获得着色器所需的实际 UV 坐标。我在想我需要生成顶点,将它们存储在一个数组中,并glVertexAttribPointer(...)
按照 UV 坐标调用一些东西,但我不确定我应该从图像中使用什么数据来获得这个,或者即使我是否已经在函数中解析了它。我想这将涉及使用内部/外部 for 循环(外部表示 x,内部表示 y)以行/列方式抓取图像。不过,我对此感到有些困惑,我不确定这是否是我需要的。
无论哪种方式,任何有关如何做到这一点的建议都将不胜感激。
解析图像的实际代码(HEADER_LENGTH
= 54 字节):
GLuint Image_LoadBmp( const char* fname, image_bmp_t* data )
{
uint8_t header[ HEADER_LENGTH ];
FILE* f = fopen( fname, "rb" );
if ( !f )
{
printf( "ERROR: file \"%s\" could not be opened [likely] due to incorrect path. :/ \n", fname );
return 0; // return false
}
data->filename = strdup( fname ); // TODO: write a wrapper for strdup which exits program on NULL returns
const size_t num_bytes_read = fread( ( void* )header, sizeof( uint8_t ), HEADER_LENGTH, f );
if ( num_bytes_read != HEADER_LENGTH )
{
printf( "ERROR: file \"%s\" could not be opened due to header size being " _SIZE_T_SPECIFIER " bytes; "\
"this is an invalid format. \n", fname, num_bytes_read );
return 0;
}
if ( header[ 0 ] != *( uint8_t* )"B" || header[ 1 ] != *( uint8_t* )"M" )
{
printf( "ERROR: file \"%s\" does NOT have a valid signature \n", fname );
return 0;
}
data->image_size = *( uint32_t* )&( header[ 0x22 ] );
data->header_size = ( uint32_t )( header[ 0x0E ] );
data->width = ( uint32_t )( header[ 0x12 ] );
data->height = ( uint32_t )( header[ 0x16 ] );
data->pixel_data_pos = ( uint32_t )( header[ 0x0A ] );
data->compression_method = ( uint8_t )( header[ 0x1E ] );
data->bpp = ( uint8_t )( header[ 0x1C ] );
// TODO (maybe): add support for other compression methods
if ( data->compression_method != CM_RGB )
{
puts( "ERROR: file \"%s\" does NOT have a supported compression method for this parser; \n" \
"\t Currently, the compression methods supported are: \n" \
"\t - BI_RGB \n\n"
);
return 0;
}
return 1;
}
根据从当前图像收集的图像信息,我的调试输出如下所示:
Info for "assets/sprites/nave/nave0001.bmp" {
Size = 3612 Header Size = 40
Width = 27 Height = 43
Pixel Array Address = 54 Compression Method = 0
Bits Per Pixel = 24
}