opengl放大 放大缩小后x y像素产生了多少位移

OpenGL模型变换和视图变换_百度知道
OpenGL模型变换和视图变换
求教,最好详细点
通常,y。三个参数分别表示了在三个坐标上的位移值。设置的方法是以GL_MODELVIEW为参数调用glMatrixMode函数,如果每次都去考虑如何把变换倒过来,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性:实际变换的顺序与代码中写的顺序是相反的: glTranslate*: glMatrixMode(GL_MODELVIEW),y,0)到 (x,坐标系统随着物体旋转。即。物体将绕着(0; 然后,这是有原因的。 以上都是针对改变物体的位置和方向来介绍的。在OpenGL中。 假设当前矩阵为单位矩阵,z分别表示在该方向上的缩放比例。进行模型和视图变换,把当前矩阵和一个表示移动物体的矩阵相乘,中间三个参数表示了观察目标的位置。这也只需要一行代码,除了配合使用glRotate*和glTranslate*函数以外。但在绘制复杂的三维图形时,初学的时候需要特别注意这一点,实际上是先进行移动,0。 注意我都是说“与XX相乘”,z)的直线,((RT)v) = (R(Tv))。 glRotate*: glLoadIdentity(),坐标系统随着物体移动,就可以进行模型变换和视图变换了,把当前矩阵和一个表示缩放物体的矩阵相乘,坐标并不是固定不变的。如果要改变观察点的位置,换句话说:gluLookAt。 让我们想象。旋转的时候,主要涉及到三个函数,实现这两种功能甚至使用的是同样的函数,然后先乘以一个表示旋转的矩阵R,最后三个参数代表从(0。由于矩阵乘法的结合率。所以。如此一来。 由于模型和视图的变换都通过矩阵运算来实现,可以让代码看起来更自然(写出的代码其实完全一样。x,y,参数angle表示旋转的角度,像这样,只是考虑问题时用的方法不同了),在进行变换前,而不是直接说“这个函数就是旋转”或者“这个函数就是移动”,马上就会讲到,然后进行旋转,应先设置当前操作的矩阵为“模型视图矩阵”。 OpenGL之所以这样设计,最后得到的矩阵再乘上每一个顶点的坐标矩阵v。它的参数比较多,我们需要在进行变换前把当前矩阵设置为单位矩阵。这里介绍另一种思路。由于“先移动后旋转”和“先旋转后移动”得到的结果很可能不同,是为了得到更高的效率,z)的直线以逆时针旋转,把当前矩阵和一个表示旋转物体的矩阵相乘,就不需要考虑代码的顺序反转的问题了,0)到(x,前三个参数表示了观察点的位置。 glScale*,它表示了观察者认为的“上”方向,也是很痛苦的事情,再乘以一个表示移动的矩阵T。移动的时候,0,经过变换得到的顶点坐标就是((RT)v),还可以使用这个函数从“相对移动”的观点来看
其他类似问题
为您推荐:
您可能关注的推广
opengl的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
OpenGL入门学习1-6(刚看了,看完红宝书前两章新手必看!!很实用多动手~强烈推荐!!)
下载积分:300
内容提示:OpenGL入门学习1-6(刚看了,看完红宝书前两章新手必看!!很实用多动手~强烈推荐!!)
文档格式:PDF|
浏览次数:264|
上传日期: 18:43:16|
文档星级:
该用户还上传了这些文档
OpenGL入门学习1-6(刚看了,看完红宝书前两章新手必看!
官方公共微信3337人阅读
计算机图形学(44)
&OpenGL像素阵列函数
& & & OpenGL中有两个函数可用于定义矩形阵列的形状或图案。一个是位图,另一个是像素图。OpenGL也提供若干的函数用于存储、复制及管理像素值阵列。
OpenGL位图函数
下面的函数定义了一个二值的阵列:
glBitmap (width, height, x0, y0, xOffset, yOffset, bitShape);& & & &函数中的参数width和height分别给出阵列bitShape的列数和行数。bitShape的每一元素赋值为0或1。值为1表示对应像素用前面设定的颜色显示;否则,对应像素不受该位图影响。(作为一个选项,可使用1表示将指定颜色与存储在刷新缓存中对应位置的颜色值相结合。)参数x0和y0定义了矩形阵列“原点”的位置。原点位置指定为bitShape的左下角,而x0和y0可正可负。另外,需要指定帧缓存中应用图案的位置。该位置称为当前光栅位置(current
raster position ),而位图在将原点置于当前光栅位置后显示。赋给xOffset和yOffset的值用做位图显示后更新帧缓存当前光栅位置的坐标位移。
& & x0, y0, xOffset, yOffset和当前光栅位置的坐标值使用浮点数格式。位图当然用整数的像素位置。但浮点数的坐标允许将一组位图以任意的间隔安排,这在某些应用如用位图字符形成字符串中很有用。
& & 可以使用下面的子程序来设定当前光栅位置:
glRasterPos* ()参数和后缀码与glVertex函数中的一样。因此,当前光栅位置在世界坐标系中给出,由观察变换将其变换到屏幕坐标系。在我们的二维例子中,可以直接使用整数屏幕坐标指定当前光栅位置的坐标。当前光栅位置的默认值是世界坐标系中的原点(0,
& & & & 位图的颜色使用glRasterPos被引用时的有效颜色。任何后来的颜色改变不会影响该位图。
& & & & 矩形位阵中每一行以8位为单位组织存放,即安排成一组8位无符号字符。但我们可以使用任何方便的网格大小来描述形状。作为一个例子,图3.61给出了一个用10行9列的网格定义位阵列,这时每行使用16个二进制位来描述。在将该图案应用于帧缓存像素时,第9列之后的所有位值均被忽略。
使用下面的程序段可将图3.61中的位图案应用于帧缓存中:
GLubyte bitShape [20] = {
0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x1c, 0x00,
0xff, 0x80, 0x7f, 0x00, 0x3e, 0x00, 0x1c, 0x00, 0x08, 0x00};
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);//Set pixel storage made.
glRasterPos2i (30, 40);
glBitmap (9, 10, 0.0, 20.0, 15.0, bitShape);& & & &bitShape的阵列值从矩形网格的底部开始逐行指定。接着使用OpenGL函数glPixelStorei设定位图的存储模式。该函数中使用参数值1表明数据值用字节边界对齐。glRasterPos用来设定当前光栅位置为(30,
40)。最后,函数glBitmap指定位阵列在阵列bitShape中给出,且该阵列有9列10行。这个阵列的原点坐标在(0.0, 0.0),即在网格的左下角。我们给出坐标位移为(20.0, 15.0),尽管在本例中该位移没有用。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:178223次
积分:5202
积分:5202
排名:第3384名
原创:348篇
转载:13篇
评论:18条
文章:23篇
阅读:31149
文章:12篇
阅读:4946
文章:25篇
阅读:3305
文章:54篇
阅读:64297
文章:35篇
阅读:10508
文章:36篇
阅读:9009
文章:13篇
阅读:2765
文章:55篇
阅读:34002
文章:27篇
阅读:3674
(4)(34)(44)(31)(31)(49)(44)(30)(6)(4)(7)(7)(1)(3)(64)(8)当前位置:& >
> 通过OpenGL ES混合模式缩放视频缓冲区来适应显示尺寸
通过OpenGL ES混合模式缩放视频缓冲区来适应显示尺寸
当开发基于软件模式的游戏时,通过缩放视频缓冲区来适应显示尺寸是最棘手的问题之一。当面对众多不同的分辨率时(比如开放环境下的Android),该问题会变得更加麻烦,作为开发人员,我们必须尝试在性能与显示质量之间找到最佳平衡点。正如我们在第2章中看到的,缩放视频缓冲区从最慢到最快共有3种类型。 软件模拟:3中类型中最慢,但最容易实现,是没有GPU的老款设备上的最佳选择。但是现在大部分智能手机都支持硬件加速。 混合模式:这种方式混合使用软件模拟(创建图像缓冲区)和硬件渲染(向显示屏绘制)两种模式。这种方法速度很快,而且可以在分辨率大于256×256的任意屏幕上渲染图像。 硬件加速模式:3种类型中最快,但最难实现。这取决于游戏的复杂程度,需要更加强劲的GPU。如果有好的硬件,这种方法就可以创造出令人震撼的质量和效果。但在终端设备比较分裂的平台上,比如Android,这将是十分艰难的选择。 这里,我们选择第二种方式,也是在终端设备分裂的平台上的最佳选择。你拥有软件渲染器,并希望将游戏适配到任意分辨率的显示屏上。此方法非常适合模拟器游戏、街机游戏、简单的射击游戏等。它在各种低端、中端、高端设备上都表现很好。下面我们开始介绍混合模式并探讨为什么这种方法更加可行。然后,将深入研究这种方法的实现,包括如何初始化surface并通过实际缩放来绘制到纹理。 1. 为什么使用混合缩放 这种缩放技术背后的原理很简单: 你的游戏根据给定的尺寸创建图像缓冲区(通常采用像素格式RGB565,即移动设备最常用的格式)。例如320×240,这是典型的模拟器尺寸。 当一张分辨率为320×240的图像需要被缩放至平板电脑的尺寸()或其他任意相同屏幕的设备时,我们可以使用软件模拟的方式来完成缩放,但会慢的令人无法忍受。而采用混合模式进行缩放,需要创建OpenGL ES纹理并将图片(320×240)渲染到GL四边形上。 纹理会通过硬件被缩放到适合显示屏的尺寸(),从而你的游戏性能将得到显著提升。 从实现的角度看,这个过程可描述如下: 初始化OpenGL ES纹理:在游戏视频被初始化的阶段,必须创建硬件surface。其中包含简单的纹理,要显示的视频图像会被渲染至到该纹理(详见代码清单1与代码清单2)。 将图像缓冲区绘制到纹理:在游戏循环的末端,渲染要显示的视频图像到纹理,该纹理会自动缩放至适合显示屏的尺寸(详见代码清单3)。 代码清单1 创建RGB656格式的空纹理 代码如下: &SPAN style="FONT-SIZE: 14px"&// 纹理ID static unsigned int mTextureID; // 被用来计算图片绘制在纹理上的X、Y偏移量
/** * 创建RGB565格式的空纹理 * 参数: (w,h) 纹理的宽, 高 * (x_offsety_offset): 图片绘制在纹理上的X、Y偏移量 */ static void CreateEmptyTextureRGB565 (int w, int h, int x_offset, int y_offset) { int size = w * h * 2; xoffset = x_ yoffset = y_ // 缓冲区 unsigned short * pixels = (unsigned short *)malloc(size); memset(pixels, 0, size); // 初始化GL状态 glDisable(GL_DITHER); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glClearColor(.5f, .5f, .5f, 1); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); // 创建纹理 glGenTextures(1, &mTextureID); glBindTexture(GL_TEXTURE_2D, mTextureID); // 纹理参数 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // RGB565格式的纹理 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_ SHORT_5_6_5 , pixels); free (pixels); } &/SPAN&
代码清单2展示了CreateEmptyTextureRGB565的实现过程,创建RGB656格式的空纹理用于绘制,参数如下: w和h:要显示的视频图片的尺寸。 x_offset和y_offset:坐标系中X轴、Y轴的偏移量,视频图片将会按照这个坐标被渲染到纹理。但是为什么我们需要这些参数?请继续阅读。 在OpenGL中创建纹理,我们只需要调用: 代码如下: &SPAN style="FONT-SIZE: 14px"&glGenTextures(1, &mTextureID); glBindTexture(GL_TEXTURE_2D, mTextureID);&/SPAN&
这里的mTextureID是整型变量,用于存储纹理的ID。然后需要设置下面这些纹理参数: GL_TEXTURE_MIN_FILTER:指定纹理缩小的方式,当像素被纹理化后并映射到某个大于单个纹理元素的区域时使用的缩小方式为GL_NEAREST,返回距离像素被纹理化后的中心最近(曼哈顿距离)的纹理元素的值。 GL_TEXTURE_MAG_FILTER:指定纹理放大的方式,当像素被纹理化后并映射到某个小于或等于单个纹理元素的区域时使用的放大方式为GL_LINEAR,返回4个距离像素被纹理化后的中心最近的纹理元素的加权平均值。 GL_TEXTURE_WRAP_S:用于设置纹理坐标系中S轴方向上的纹理映射方式为GL_CLAMP,将纹理坐标限制在(0,1)范围内,当映射单张图像到对象时,可以有效防止画面重叠。 GL_TEXTURE_WRAP_T:用于设置纹理坐标系中T轴方向上的纹理映射的方式为GL_CLAMP。 最后,我们通过glTexImage2D函数及以下参数来指定二维纹理: GL_TEXTURE_2D:指定目标纹理的类型为二维纹理。 Level:指定图像纹理的详细程度。0是最基本的图像纹理层。 Internal format:指定纹理的颜色成分,在这个例子中是RGB格式。 Width and height:纹理的尺寸,必须是2的幂。 Format:指定像素数据的格式,同时也必须与内部格式相同。 Type:指定像素数据的数据类型,在本例中使用RGB565(16位)格式。 Pixels:指向内存中图像数据的指针,必须使用RGR656编码。 注意:纹理的尺寸必须是2的幂,如256、512、1024等。但是,要显示的视频图像的尺寸可以是任意尺寸。这就意味着,纹理的尺寸必须是大于或等于要显示的视频图像尺寸的2的幂。稍后我们将进行详细介绍。 现在,让我们来看一看混合视频缩放的实际实现,接下来的两个小节将介绍如何初始化用来缩放的surface以及如何实现实际的绘制。 2. 初始化surface 要进行缩放,就必须保证纹理的尺寸大于或等于要显示的视频图像的尺寸。否则,当图像渲染的时候,会看到白色或黑色的屏幕。在代码清单2中,JNI_RGB565_SurfaceInit函数将确保产生有效的纹理尺寸。使用图像的宽度和高度为参数,然后调用getBestTexSize函数来获取最接近要求的纹理尺寸,最后通过调用CreateEmptyTextureRGB565函数来创建空的纹理。注意,如果图像尺寸小于纹理尺寸,就通过计算X、Y坐标的偏移量来将其置于屏幕的中心。 代码清单2 初始化surface 代码如下: &SPAN style="FONT-SIZE: 14px"&// 获取下一个POT纹理尺寸,该尺寸大于或等于图像尺寸(WH) static void getBestTexSize(int w, int h, int *tw, int *th) { int width = 256, height = 256; #define MAX_WIDTH 1024 #define MAX_HEIGHT 1024 while ( width & w && width & MAX_WIDTH) { width *= 2; } while ( height & h && height & MAX_HEIGHT) { height *= 2; } *tw = *th = } /** * 初始化RGB565 surface * 参数: (w,h) 图像的宽高 */ void JNI_RGB565_SurfaceInit(int w, int h) { //最小纹理的宽高 int texw = 256; int texh = 256; // 得到纹理尺寸 (必须是POT) &= WxH getBestTexSize(w, h, &texw, &texh); // 图片在屏幕中心? int offx = texw & w ? (texw - w)/2 : 0; int offy = texh & h ? (texh - h)/2 : 0; if ( w & texw || h & texh) printf ("Error: Invalid surface size %sx%d", w, h); // 创建OpenGL纹理,用于渲染 CreateEmptyTextureRGB565 (texw, texh, offx, offy); } &/SPAN&
3. 绘制到纹理 最后,为了将图像显示到屏幕上(也称作surface翻转),我们调用JNI_RGB565_Flip函数,其参数是像素数组(使用RGR656编码)和要显示的图像尺寸。JNI_RGB565_Flip函数通过调用DrawIntoTextureRGB565将图像绘制到纹理并交换缓冲区。注意交换缓冲区的函数是用Java编码的,而不是用C语言编码的,因此我们需要一个方法来调用Java的交换函数。我们可以通过使用JNI方法调用某个Java方法来完成缓冲区的交换工作(见代码清单3)。 代码清单3 用四边形将图像缓冲区绘制到纹理 代码如下: &SPAN style="FONT-SIZE: 14px"&// 四边形顶点的X、Y和Z坐标 static const float vertices[] = { -1.0f, -1.0f, 0, 1.0f, -1.0f, 0, 1.0f, 1.0f, 0, -1.0f, 1.0f, 0 }; // 四边形坐标(0-1) static const float coords[] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, }; // 四边形顶点索引 static const unsigned short indices[] = { 0, 1, 2, 3}; /** * 使用四边形像素(RGB565的unsigned short)将像素数组绘制到全部屏幕 * */ static void DrawIntoTextureRGB565 (unsigned short * pixels, int w, int h) { // 清除屏幕 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 启用顶点和纹理坐标 glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mTextureID); glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 , pixels); // 绘制四边形 glFrontFace(GL_CCW); glVertexPointer(3, GL_FLOAT, 0, vertices); glEnable(GL_TEXTURE_2D); glTexCoordPointer(2, GL_FLOAT, 0, coords); glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, indices); } // 翻转surface (绘制到纹理中) void JNI_RGB565_Flip(unsigned short *pixels , int width, int height) { if ( ! pixels) {
} DrawIntoTextureRGB565 (pixels, width, height); // 在这里必须交换GLES缓冲区 jni_swap_buffers (); } &/SPAN&
使用OpenGL渲染到纹理: (1) 使用glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT)清除颜色与深度缓冲区。 (2) 启用客户端状态:当glDrawElements函数被调用时,写入顶点数组与纹理坐标数组。 (3) 通过glActiveTexture函数选择要激活的纹理单元,初始值是GL_TEXTURE0。 (4) 将已经生成的纹理绑定到等待被纹理化的目标。GL_TEXTURE_2D (一个二维纹理)是默认的纹理绑定目标,mTextureID是纹理的ID。 (5) 通过glTexSubImage2D函数来指定二维纹理子图,参数如下: GL_TEXTURE_2D:指定目标纹理类型。 level:指定图像的详细程度(即层数)。0是基本的图像纹理层。 Xoffset:指定纹理像素在X轴方向上、纹理数组内的偏移量。 Yoffset:指定纹理像素在Y轴方向上、纹理数组内的偏移量。 width:指定纹理子图的宽度。 height:指定纹理子图的高度 format:指定像素数据的格式。 Type:指定像素数据的数据类型。 data:指定指向内存中图像数据的指针。 (6) 通过调用以下函数绘制四边形顶点、坐标与索引: glFrontFace:启用四边形的正面。 glVertexPointer:定义四边形的顶点数据数组,顶点数据大小为3,数据类型是GL_FLOAT,数组中每个顶点间的间隔(步长)为0。 glTexCoordPointer:定义四边形的纹理数组,纹理坐标大小为2,数据类型是GL_FLOAT,间隔为0。 glDrawElements:通过数据数组以三角形扇(GL_TRIANGLE_FAN)的方式渲染多边形,有4个顶点,类型为短整型(GL_UNSIGNED_SHORT),外加指向索引的指针。 注意,从代码清单3中我们可以看到四边形的两个轴坐标都在[&#]区间内。这是因为OpenGL的坐标系统在(&#)之间,原点(0,0)在窗口中心(如图3-10所示)。 &在理想的世界里,我们不应该过多地担心视频缓冲区的尺寸(尤其是使用软件模拟仅有的定标器/渲染器)。当在Android中使用OpenGL缩放视频时,这却是事实。在这个示例中,缓冲区的尺寸至关重要。接下来你将学习如何处理任意尺寸的视频,这一点在OpenGL中工作得不是很好。 4. 当图像的尺寸不是2的幂时会发生什么 如前所述,当图像的尺寸是2的幂时混合缩放会非常完美。但是,也有可能图像缓冲区不是2的幂。例如,在处理Demo引擎的章节中有一段320×240尺寸的视频。在这种情况下,图像仍然被缩放,但是会缩放到纹理尺寸的百分比大小。在图2和3中可以看到这个效果。 &在图2中,有以下尺寸: 设备显示器:859×480 纹理:512×256 图像:320×240 正如我们看到的一样,图像被缩放到纹理宽度的62%(320/512*100)和高度的93% (240/256*100)。因此,在任何分辨率大于256的设备上,图像都会被缩放到设备提供分辨率的62%×93%。现在我们来看看图3。 &图3 缩放尺寸为2的幂的图像 在图3中,有以下尺寸: 设备显示器:859×480 纹理:512×256 图像:512×256 缩放和绘制 在图3中,我们看见图像被缩放到设备提供分辨率的100%,这正是我们想要的。但是如果图像不是2的幂,那么我们要如何做呢?为了解决这个问题,我们应该: (1) 用软件缩放器将320×240尺寸的图像缩放到接近2的幂(这里是512×256)。 (2) 将已缩放的surface转换成RGB656格式的图像,以兼容前面介绍的DrawInto-TextureRGB565。 (3) 绘制到纹理,从而使用硬件将其缩放到显示屏的分辨率。 这种解决办法可能比前面介绍的方法慢,但仍然比纯软件缩放快,尤其是运行在高分辨率设备时更明显(如平板电脑)。 代码清单4展示了如何使用流行的SDL_gfx库来缩放SDL surface。 代码清单4 用SDL_gfx库缩放图像 代码如下: &SPAN style="FONT-SIZE: 14px"&void JNI_Flip(SDL_Surface *surface ) { if ( zoom ) { // 如果surface是8位缩放,就是8位,否则surface就是32的RGBA! SDL_Surface * sized = zoomSurface( surface, zoomx, zoomy, SMOOTHING_OFF); JNI_FlipByBPP (sized); // 必须清理掉! SDL_FreeSurface(sized); } else { JNI_FlipByBPP (surface); } }&/SPAN&
缩放和绘制实现 要放大/缩小SDL surface,需要简单地调用SDL_gfx库的zoomSurface: (1) 一个SDL surface。 (2) 水平缩放因子:(0-1) (3) 垂直缩放因子:(0-1) (4) SMOOTHING_OFF:为了能快速绘制,禁用反锯齿处理。 接下来,让我们基于分辨率(每个像素的位数)来翻转SDL surface。代码清单5展示了如何完成8位RBG格式的surface。 代码清单5 根据分辨率翻转SDL surface 代码如下: &SPAN style="FONT-SIZE: 14px"&/** * 通过每个像素的位数翻转SDL surface */ static void JNI_FlipByBPP (SDL_Surface *surface) { int bpp = surface-&format-&BitsPerP switch ( bpp ) { case 8: JNI_Flip8Bit (surface);
case 16: // 替换16位RGB (surface);
case 32: // 替换32为RGB (surface);
default: printf("Invalid depth %d for surface of size %dx%d", bpp, surface-&w, surface-&h); } } /** * 替换8位SDL surface */ static void JNI_Flip8Bit(SDL_Surface *surface ) {
int size = surface-&w * surface-&h; int bpp = surface-&format-&BitsPerP unsigned short pixels [size]; // RGB565 SDL_Color * colors = surface-&format-&palette-& for ( i = 0 ; i & i++ ) { unsigned char pixel = ((unsigned char *)surface-&pixels)[i]; pixels[i] = ( (colors[pixel].r && 3) && 11) | ( (colors[pixel].g && 2) && 5) | (colors[pixel].b && 3); // RGB565 } DrawIntoTextureRGB565 (pixels, surface-&w, surface-&h); jni_swap_buffers (); } &/SPAN&
指定SDL surface,然后检查每个像素的格式:surface-&format-&BitsPerPixel,并根据该值创建能够被DrawIntoTextureRGB565使用的RGB565像素数组: 代码如下: &SPAN style="FONT-SIZE: 14px"&for ( i = 0 ; i & i++ ) { unsigned char pixel = ((unsigned char *)surface-&pixels)[i]; // RGB565 pixels[i] = ( (colors[pixel].r && 3) && 11) | ( (colors[pixel].g && 2) && 5) | (colors[pixel].b && 3); }&/SPAN&
从surface调色板上提取每个像素包含的红、绿和蓝值: 代码如下: &SPAN style="FONT-SIZE: 14px"&SDL_Color * colors = surface-&format-&palette-& RED: colors[pixel].r GREEN: colors[pixel].g BLUE: colors[pixel].b&/SPAN&
为了构建RGB565像素,需要从每个颜色组件中抛弃最低有效位: 代码如下: &SPAN style="FONT-SIZE: 14px"&colors[pixel].r && 3 (8 -3 = 5) colors[pixel].g && 2 (8 C 2 = 6) colors[pixel].b && 3 (8 C 3 = 5)&/SPAN&
然后移动每个组件到16位值的正确位置(5+6+5= 16――因此是RGB656): 代码如下: &SPAN style="FONT-SIZE: 14px"&pixels[i] = (RED && 11) | (GREEN && 5) | BLUE&/SPAN&
最后将新的数组和图像宽度、高度一起发送到DrawIntoTextureRGB565。最后一个问题,我们需要一种方式来告诉surface是否需要缩放。当surface在第一次被创建时将完成视频初始化。代码清单6展示了如何用SDL创建软件surface。 代码清单6 初始化缩放surface 代码如下: &SPAN style="FONT-SIZE: 14px"&// 应该被缩放? static char zoom = 0; // 缩放范围[0,1] static double zoomx = 1.0; static double zoomy = 1.0; /********************************************************** * 图像的构造函数 * 图像必须是2的幂 (256×256, 512×256,...) * 以便用OpenGL纹理进行全屏渲染。如果图像不是 * POT (320×240),那么它将被缩放 **********************************************************/ SDL_Surface * JNI_SurfaceNew(int width, int height, int bpp, int flags) { Uint32 rmask = 0, gmask = 0, bmask =0 , amask = 0; // 纹理尺寸和偏移量 int realw = 256, realh = 256, offx = 0, offy = 0; // 图像必须是2的幂以便OpenGL能缩放它 if ( width & 512 ) { Sys_Error("ERROR: INVALID IMAGE WIDTH %d (max POT 512×512)", width); } // 真实的W/H必须接近POT值的w/h // 将要缩放到512×256 // 应该是256,但是512的分辨率更高(更慢) if ( width & 256 ) realw = 512; // 大小不是POT,就缩放到接近于POT,可选择: // 256×256 (快/分辨率低) 512×256 (分辨率较高/较慢) // 512×512 最慢 if ( ( width != 512 && width != 256) || ( height != 256 ) ) { zoom = 1; zoomx = realw / (float) zoomy = realh / (float) offx = offy = 0; printf("WARNING Texture of size %dx%d will be scaled to %dx%d zoomx=%.3f zoomy=%.3f" , width, height, realw, realh, zoomx, zoomy); } // 创建渲染器使用的OpenGL纹理 CreateEmptyTextureRGB565 (realw, realh, offx, offy); // 这是真正的被用于客户端渲染视频的surface return SDL_CreateRGBSurface (SDL_SWSURFACE, width, height, bpp, rmask, gmask, bmask, amask); } &/SPAN&
如果图像的尺寸不是2的幂,那么缩放标志将被设为1,并且水平和垂直方向的缩放因子将开始计算。然后,通过调用CreateEmptyTextureRGB565,根据宽度、高度和纹理的X、Y位移量来创建空纹理。最后调用SDL_CreateRGBSurface以创建SDL surface: SDL_SWSURFACE:告诉SDL创建软件surface。 width和height:定义surface的尺寸。 bpp:定义surface中每个像素(分辨率)的位数(8、16、24和32)。 rmask、gmask、bmask和amask:这些是每个像素格式的红、绿、蓝和alpha(透明度)的掩码值。设置为0来让SDL注意到它(译者注:设置为0,OpenGL就可以写入;设置为1,则不能写入)。 混合缩放的经验法则 总而言之,当在游戏中像这样使用混合缩放时,请牢记以下经验法则: 如果可以,就总是设置视频的大小为2的幂:256×256或512×56。高于512对于这种技术来说代价太高。 如果不想设置视频的尺寸,但又想全屏显示,就可以像前面提到的那样,用SDL软件缩放到最接近的2的幂,然后再使用硬件进行缩放。 如果视频的尺寸大于512×512,混合缩放技术就未必有效(性能需要)。

我要回帖

更多关于 opengl放大 的文章

 

随机推荐