转自【翻译】NeHe OpenGL 教程

前言

声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改。对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢。

NeHe OpenGL第二十九课:Blt函数

Blitter 函数:

类似于DirectDraw的blit函数,过时的技术,我们有实现了它。它非常的简单,就是把一块纹理贴到另一块纹理上。

这篇文章是有Andreas Lffler所写的,它写了一份原始的教程。过了几天,Rob Fletcher发了封邮件给我,他重新改写了所有的代码,我在它的基础上把glut的框架变换为Win32的框架。 
现在让我们开始吧!

下面是一个保存图像数据的结构  
   
typedef struct Texture_Image
{
 int width;         // 宽
 int height;         // 高
 int format;         // 像素格式
 unsigned char *data;        // 纹理数据
} TEXTURE_IMAGE;

接下来定义了两个指向这个结构的指针  
   
typedef TEXTURE_IMAGE *P_TEXTURE_IMAGE;

P_TEXTURE_IMAGE t1;         // 指向保存图像结构的指针
P_TEXTURE_IMAGE t2;         // 指向保存图像结构的指针

下面的函数为w*h的图像分配内存  
   
P_TEXTURE_IMAGE AllocateTextureBuffer( GLint w, GLint h, GLint f)
{
 P_TEXTURE_IMAGE ti=NULL;       
 unsigned char *c=NULL;        
 ti = (P_TEXTURE_IMAGE)malloc(sizeof(TEXTURE_IMAGE));     // 分配图像结构内存

if( ti != NULL ) {
  ti->width  = w;        // 设置宽度
  ti->height = h;        // 设置高度
  ti->format = f;        // 设置格式
  // 分配w*h*f个字节
  c = (unsigned char *)malloc( w * h * f); 
  if ( c != NULL ) {
   ti->data = c;
  }
  else {
   MessageBox(NULL,"内存不足","分配图像内存错误",MB_OK | MB_ICONINFORMATION);
   return NULL;
  }
 }

else
 {
  MessageBox(NULL,"内存不足","分配图像结构内存错误",MB_OK | MB_ICONINFORMATION);
  return NULL;
 }
 return ti;         // 返回指向图像数据的指针
}

下面的函数释放分配的内存  
   
// 释放图像内存
void DeallocateTexture( P_TEXTURE_IMAGE t )
{
 if(t)
 {
  if(t->data)
  {
   free(t->data);       // 释放图像内存
  }

free(t);         // 释放图像结构内存
 }
}

下面我们来读取*.raw的文件,这个函数有两个参数,一个为文件名,另一个为保存文件的图像结构指针。  
   
// 读取*.RAW文件,并把图像文件上下翻转一符合OpenGL的使用格式。
int ReadTextureData ( char *filename, P_TEXTURE_IMAGE buffer)
{
 FILE *f;
 int i,j,k,done=0;
 int stride = buffer->width * buffer->format;     // 记录每一行的宽度,以字节为单位
 unsigned char *p = NULL;

f = fopen(filename, "rb");       // 打开文件
 if( f != NULL )        // 如果文件存在
 {

如果文件存在,我们通过一个循环读取我们的纹理,我们从图像的最下面一行,一行一行的读取图像。  
   
  for( i = buffer->height-1; i >= 0 ; i-- )    // 循环所有的行,从最下面以行开始,一行一行的读取
  {
   p = buffer->data + (i * stride );
   for ( j = 0; j < buffer->width ; j++ )   // 读取每一行的数据
   {

下面的循环读取每一像素的数据,并把alpha设为255

for ( k = 0 ; k < buffer->format-1 ; k++, p++, done++ )
    {
     *p = fgetc(f);     // 读取一个字节
    }
    *p = 255; p++;      // 把255存储在alpha通道中
   }
  }
  fclose(f);        // 关闭文件
 }

如果出现错误,弹出一个提示框

else      
 {
  MessageBox(NULL,"不能打开文件","图像错误",MB_OK | MB_ICONINFORMATION);
 }
 return done;         // 返回读取的字节数
}

下面的代码创建一个2D纹理,和前面课程介绍的方法相同  
   
void BuildTexture (P_TEXTURE_IMAGE tex)
{
 glGenTextures(1, &texture[0]);
 glBindTexture(GL_TEXTURE_2D, texture[0]);
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, tex->width, tex->height, GL_RGBA, GL_UNSIGNED_BYTE, tex->data);
}

现在到了blitter函数的地方了,他运行你把一个图像的任意部分复制到另一个图像的任意部分,并混合。
src为原图像
dst为目标图像
src_xstart,src_ystart为要复制的部分在原图像中的位置
src_width,src_height为要复制的部分的宽度和高度
dst_xstart,dst_ystart为复制到目标图像时的起始位置
上面的意思是把原图像中的(src_xstart,src_ystart)-(src_width,src_height)复制到目标图像中(dst_xstart,dst_ystart)-(src_width,src_height)
blend设置是否启用混合,0为不启用,1为启用
alpha设置源图像中颜色在混合时所占的百分比   
   
void Blit( P_TEXTURE_IMAGE src, P_TEXTURE_IMAGE dst, int src_xstart, int src_ystart, int src_width, int src_height,
    int dst_xstart, int dst_ystart, int blend, int alpha)
{
 int i,j,k;
 unsigned char *s, *d;

// 掐断alpha的值
 if( alpha > 255 ) alpha = 255;
 if( alpha < 0 ) alpha = 0;

// 判断是否启用混合
 if( blend < 0 ) blend = 0;
 if( blend > 1 ) blend = 1;

d = dst->data + (dst_ystart * dst->width * dst->format);     // 要复制的像素在目标图像数据中的开始位置 
 s = src->data + (src_ystart * src->width * src->format);   // 要复制的像素在源图像数据中的开始位置

for (i = 0 ; i < src_height ; i++ )      // 循环每一行
 {

s = s + (src_xstart * src->format);     // 移动到下一个像素
  d = d + (dst_xstart * dst->format);    
  for (j = 0 ; j < src_width ; j++ )     // 循环复制一行
  {

for( k = 0 ; k < src->format ; k++, d++, s++)   // 复制每一个字节
   {
    if (blend)      // 如果启用了混合
     *d = ( (*s * alpha) + (*d * (255-alpha)) ) >> 8; // 根据混合复制颜色
    else       
     *d = *s;      // 否则直接复制
   }
  }
  d = d + (dst->width - (src_width + dst_xstart))*dst->format;  // 移动到下一行
  s = s + (src->width - (src_width + src_xstart))*src->format;  
 }
}

初始化代码基本不变,我们使用新的函数,加载*.raw纹理。并把纹理t2的一部分blit到t1中混合,接着按常规的方法设置2D纹理。  
   
int InitGL(GLvoid) 
{
 t1 = AllocateTextureBuffer( 256, 256, 4 );      // 为图像t1分配内存
 if (ReadTextureData("Data/Monitor.raw",t1)==0)     // 读取图像数据
 {          // 失败则弹出对话框
  MessageBox(NULL,"不能读取 'Monitor.raw' 文件","读取错误",MB_OK | MB_ICONINFORMATION);
  return FALSE;
 }

t2 = AllocateTextureBuffer( 256, 256, 4 );      // 为图像t2分配内存
 if (ReadTextureData("Data/GL.raw",t2)==0)      // 读取图像数据
 {          // 失败则弹出对话框
  MessageBox(NULL,"不能读取 'GL.raw' 文件","读取错误 ",MB_OK | MB_ICONINFORMATION);
  return FALSE;
 }

把图像t2的(127,127)-(256,256)部分和图像t1的(64,64,196,196)部分混合  
   
 // 把图像t2的(127,127)-(256,256)部分和图像t1的(64,64,196,196)部分混合
 Blit(t2,t1,127,127,128,128,64,64,1,127);

下面的代码和前面一样,释放分配的空间,创建纹理  
   
 BuildTexture (t1);        // 把t1图像加载为纹理

DeallocateTexture( t1 );       // 释放图像数据
 DeallocateTexture( t2 );

glEnable(GL_TEXTURE_2D);       // 使用2D纹理

glShadeModel(GL_SMOOTH);       // 使用光滑着色
 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);     // 设置背景色为黑色
 glClearDepth(1.0);        // 设置深度缓存清楚值为1
 glEnable(GL_DEPTH_TEST);       // 使用深度缓存
 glDepthFunc(GL_LESS);       // 设置深度测试函数

return TRUE;
}

下面的代码绘制一个盒子  
   
GLvoid DrawGLScene(GLvoid)
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 清楚颜色缓存和深度缓存
 glLoadIdentity();       
 glTranslatef(0.0f,0.0f,-5.0f);

glRotatef(xrot,1.0f,0.0f,0.0f);
 glRotatef(yrot,0.0f,1.0f,0.0f);
 glRotatef(zrot,0.0f,0.0f,1.0f);

glBindTexture(GL_TEXTURE_2D, texture[0]);

glBegin(GL_QUADS);
  // 前面
  glNormal3f( 0.0f, 0.0f, 1.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
  // 后面
  glNormal3f( 0.0f, 0.0f,-1.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
  glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
  // 上面
  glNormal3f( 0.0f, 1.0f, 0.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
  // 下面
  glNormal3f( 0.0f,-1.0f, 0.0f);
  glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
  // 右面
  glNormal3f( 1.0f, 0.0f, 0.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
  glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
  // 左面
  glNormal3f(-1.0f, 0.0f, 0.0f);
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
  glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
  glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
 glEnd();

xrot+=0.3f;
 yrot+=0.2f;
 zrot+=0.4f;
 return TRUE; // 一切 OK
}

KillGLWindow() 函数没有变化  
   
CreateGLWindow函数没有变化  
   
WinMain() 没有变化 
原文及其个版本源代码下载:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=29

没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。
本文转自wenglabs博客园博客,原文链接:http://www.cnblogs.com/arxive/p/6239512.html,如需转载请自行联系原作者

NeHe OpenGL教程 第二十九课:Blt函数相关推荐

  1. NeHe OpenGL教程 第二十六课:反射

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  2. NeHe OpenGL第三十九课:物理模拟

    NeHe OpenGL第三十九课:物理模拟 物理模拟简介: 还记得高中的物理吧,直线运动,自由落体运动,弹簧.在这一课里,我们将创造这一切.   物理模拟介绍 如果你很熟悉物理规律,并且想实现它,这篇 ...

  3. NeHe OpenGL教程 第十五课:纹理图形字

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  4. NeHe OpenGL第二十九课:Blt函数

    NeHe OpenGL第二十九课:Blt函数 Blitter 函数: 类似于DirectDraw的blit函数,过时的技术,我们有实现了它.它非常的简单,就是把一块纹理贴到另一块纹理上. 这篇文章是有 ...

  5. NeHe OpenGL第三十二课:拾取游戏

    NeHe OpenGL第三十二课:拾取游戏 拾取, Alpha混合, Alpha测试, 排序: 这又是一个小游戏,交给的东西会很多,慢慢体会吧   欢迎来到32课. 这课大概是在我所写作已来最大的一课 ...

  6. NeHe OpenGL第三十五课:播放AVI

    NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错. ...

  7. python第二十九课——文件读写(复制文件)

    自定义函数:实现文件复制操作有形参(2个) 没有返回值相似版(不用) def copyFile(src,dest):#1.打开两个文件:1个关联读操作,1个关联写操作fr=open(src,'rb') ...

  8. NeHe OpenGL第四十六课:全屏反走样

    NeHe OpenGL第四十六课:全屏反走样 全屏反走样 当今显卡的强大功能,你几乎什么都不用做,只需要在创建窗口的时候该一个数据.看看吧,驱动程序为你做完了一切.   在图形的绘制中,直线的走样是非 ...

  9. NeHe OpenGL第四十四课:3D光晕

    NeHe OpenGL第四十四课:3D光晕 3D 光晕 当镜头对准太阳的时候就会出现这种效果,模拟它非常的简单,一点数学和纹理贴图就够了.好好看看吧.   大家好,欢迎来到新的一课,在这一课中我们将扩 ...

最新文章

  1. 为什么信不过AI看病?数据集小、可靠性差,AI医疗任重道远
  2. 并发编程-14线程安全策略之并发容器(J.U.C)中的集合类
  3. 健身前到底该不该吃东西
  4. asp 中使用Ftp.exe 上传大文件
  5. Packer创建阿里云本地镜像
  6. 组播穿越MPLS ***+SSM
  7. 当机器人具有自我知觉,并能自适应环境,真的不可怕吗?
  8. 在Windows上搭建Go开发环境
  9. gsonformat插件_没用过这些IDEA插件?怪不得写代码头疼
  10. Oracle数据库学习笔记(四)--Oracle体系结构
  11. ovito在linux下安装教程,linux下超详细教程安装phonopy
  12. python 64式: 第28式、分布式锁与群组管理__3、tooz应用之分布式锁
  13. Google Analytics API V4(谷歌统计实战)
  14. 全国十大加班城市排行榜加班最疯狂的城市
  15. 这样创建EC2实例,才算没浪费AWS的一年免费套餐
  16. 一些有用的Latex模板(持续更新)
  17. java quartz 重启不了_java – 重新启动quartz调度程序而不会出现错误
  18. 【无标题】华为ict网络赛道练习题
  19. android 代码等待一秒,【报Bug】安卓微信旧版本7.0.2 ,支付完成,等待几秒后,再点击完成 回到小程序,跳转不了页面。...
  20. 【微信小程序】---- redux 在原生微信小程序的使用实例

热门文章

  1. 解决问题(九)——jsf+facelet(一)下马威
  2. 130242014047-徐晓敏-实验一
  3. python animation 轨迹_在jupyter noteb之外显示动画
  4. 游戏用户隐私协议《贪吃鱼进化》
  5. 大三老学姨想说。。。
  6. Untiy 游戏存档PlayerPrefs
  7. 原创《基于深度特征学习的细粒度图像分类研究综述》
  8. BTC源码分析 交易(一)
  9. ol-ext transform 对象,旋转、拉伸、放大(等比例缩放),事件监听
  10. IDEAd的web工程配置