2013-01-15 33 views
1

我一直在研究位图加载器,其主要目标只是解析数据并在OpenGL中渲染它。我现在需要在x/y(即逐个像素)的基础上绘制像素(至少,这是我认为就渲染而言我需要做的事情)。我已经绑定了纹理对象,并调用glTexImage2D(...)关于逐像素渲染位图算法的建议

目前,我遇到的问题是像素逐像素算法。

据我了解,位图(又名DIB)文件存储颜色数据在所谓的像素阵列。每行像素由x个字节组成,每个像素的字节数可以由4(每像素32位),3(每像素24位),2(每像素16位)或1(8位每像素)。

我认为需要通过像素循环,同时计算像素阵列内的右偏移量,这是相对于其像素x/y坐标。这是真的吗?如果不是,我该怎么办?老实说,我对于是否尽管在this question I asked sometime ago中做了什么指示,但是这个方法是正确的,我对此略有困惑。

我认为逐个像素绕了一个像素是正确的做法,主要是因为 渲染与glVertex*glTexCoord*产生无非是变灰矩形多四(在我认为的OpenGL会处理这个问题的时候本身,因此为什么试图在第一个地方)。

我还应该注意,虽然我的问题显示OpenGL 3.1着色器,但我转移到了SDL 1.2 ,因此我可以暂时使用即时模式,直到我实现了正确的算法,然后切换回现代GL 。


测试图像我解析:

bitmap image

这是数据输出(由于pastebinned其长度非常长): http://pastebin.com/6RVhAVRq

和代码

void R_RenderTexture_PixByPix(texture_bmp_t* const data, const vec3 center) 
{ 


    glBindTexture(GL_TEXTURE_2D, data->texbuf_id); 

    glBegin(GL_POINTS); 
    { 
     const unsigned width = data->img_data->width + (unsigned int) center[ VEC_X ]; 
     const unsigned height = data->img_data->height + (unsigned int) center[ VEC_Y ]; 

     const unsigned bytecount = GetByteCount(data->img_data->bpp); 

     const unsigned char* pixels = data->img_data->pixels; 

     unsigned color_offset = 0; 
     unsigned x_pixel; 

     for (x_pixel = center[ VEC_X ]; x_pixel < width; ++x_pixel) 
     { 
      unsigned y_pixel; 

      for (y_pixel = center[ VEC_Y ]; y_pixel < height; ++y_pixel) 
      { 

      } 

      const bool do_color_update = true; //<--- replace true with a condition which checks to see if the color needs to be updated. 

      if (do_color_update) 
      { 
       glColor3fv(pixels + color_offset); 
      } 

      color_offset += bytecount; 
     } 
    } 
    glEnd(); 

    glBindTexture(GL_TEXTURE_2D, 0); 
} 
+1

但你为什么要像素逐像素?绘制一个大小合适的四边形(使用4个顶点)并不会更好。正确意味着最终的四元组将匹配位图的大小。 – fen

+0

@fan,这实际上是我尝试做的......这让我感到困惑,主要是因为结果是一个灰色的矩形。 – zeboidlund

回答

2

您完全忽略了代码中的OpenGL纹理。纹理为你保存图像,光栅化器为你完成像素数据的所有迭代。无需自己编写一个缓慢的像素推动器循环。

由于您的代码现在立即表明纹理完全是假的,什么也不做。你可以完全忽略对glBindTexture的调用,它可以继续工作 - 或者不工作,因为你实际上没有绘制任何东西,你只需设置glColor状态。绘制一些你必须调用glVertex的东西。

那么为什么不利用现代GPU的像素推动性能,并实际使用纹理?这个怎么样:

void R_RenderTexture_PixByPix(texture_bmp_t* const data, const vec3 center) 
{ 
    if(0 == data->texbuf_id) { 
     glGenTextures(1, &(data->texbuf_id)); 
     glBindTexture(GL_TEXTURE_2D, data->texbuf_id); 

     glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 
     // there are a few more, but the defaults are ok 
     // if you didn't change them no need for further unpack settings 

     GLenum internal_format; 
     GLenum format; 
     GLenum type; 
     switch(data->img_data->bpp) { 
     case 8: 
      // this could be a palette or grayscale 
      internal_format = GL_LUMINANCE8; 
      format = GL_LUMINANCE; 
      type = GL_UNSIGNED_BYTE; 
      break; 

     case 15: 
      internal_format = GL_RGB5; 
      format = GL_BGR; // BMP files have BGR pixel order 
      type = GL_UNSIGNED_SHORT_1_5_5_5; 
      break; 

     case 16: 
      internal_format = GL_RGB8; 
      format = GL_BGR; // BMP files have BGR pixel order 
      type = GL_UNSIGNED_SHORT_5_6_5; 
      break; 

     case 24: 
      internal_format = GL_RGB8; 
      format = GL_BGR; // BMP files have BGR pixel order 
      type = GL_UNSIGNED_BYTE; 
      break; 

     case 32: 
      internal_format = GL_RGB8; 
      format = GL_BGR; // BMP files have BGR pixel order 
      type = GL_UNSIGNED_INT_8_8_8_8; 
      break; 

     } 

     glTexImage2D(GL_TEXTURE_2D, 0, internal_format, 
         data->img_data->width, data->img_data->height, 0, 
         format, type, data->img_data->pixels); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    } else { 
     glBindTexture(GL_TEXTURE_2D, data->texbuf_id); 
    } 


    static GLfloat verts[] = { 
      0, 0, 
      1, 0, 
      1, 1, 
      0, 1 
    };  
    // the following is to address texture image pixel centers 
    // tex coordinates 0 and 1 are not on pixel centers! 
    float const s0 = 1./(2.*tex_width); 
    float const s1 = (2.*(tex_width-1) + 1.)/(2.*tex_width); 
    float const t0 = 1./(2.*tex_height); 
    float const t1 = (2.*(tex_height-1) + 1.)/(2.*tex_height); 
    GLfloat texcoords[] = { 
      s0, t0, 
      s1, t0, 
      s1, t1, 
      s0, t1 
    }; 

    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

    glEnable(GL_TEXTURE_2D); 

    glVertexPointer(2, GL_FLOAT, 0, verts); 
    glTexCoordPointer(2, GL_FLOAT, 0, texcoords); 

    glColor4f(1., 1., 1., 1.); 
    glDrawArrays(GL_QUADS, 0, 4); 

    glDisableClientState(GL_VERTEX_ARRAY); 
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); 

    glBindTexture(GL_TEXTURE_2D, 0); 
} 
1

你的直觉基本上是正确的。像素以字节数组的形式存储,但字节排列成连续的组,每组代表一个像素。为了解决单个像素,你需要做的的计算是这样的:

unsigned char* image_data = start_of_pixel_data; 
unsigned char* pixel_addr = image_data + bytes_per_pixel * (y * width_in_pixels + x); 

要小心以像素为单位的宽度,因为有时是填充在该行的结束,使总排宽度字节最大为4/8/16/32/64 /等的倍数。我建议首先以十六进制查看位图的实际字节,以了解发生了什么。这是一个很好的学习练习,它会让你对你的像素行走代码有很高的信心,这正是你想要的。您可能可以使用调试器来执行此操作,或者在图像字节上使用printf写一个简单的循环。

+0

谢谢,我感谢您的帮助和建议。 – zeboidlund