|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2005-8-8 12:12:46
|
显示全部楼层
首先,Init函数创建一个拥有4个顶点的顶点缓冲,它是那么清晰明了(传入缓冲的大小、顶点的类型、缓冲的地址,最后CreateVertexBuffer函数会填写你的顶点缓冲然后返回它)。
First, the Init function creates a vertex buffer with four points. This is a fairly straightforward function (receives the size of the buffer, the type of vertex, the memory pool to grab it from, and the pointer used to return the buffer).
接下来,我们通过Lock来锁定创建的顶点缓冲,以此得到直接操作的权限。Lock函数返回一个指针,用来让我们往里面填写数据。
Next, the buffer is locked so that we have access to the actual data. The lock function returns the pointer to our data.
然后,正确地填写每一个顶点的值。需要注意的是,所有在屏幕上的坐标,都是基于-1.0和1.0之间的。很明显,第3个值是指的Z Buffer,它基于0.0和1.0之间。
After that, we set each vertex to the correct values. All position values are based on the assumption that the screen goes from -1.0 to 1.0 in both the X and Y direction, with the origin at the center of the screen. The third value is, of course, the Z value, and has valid values of 0.0 to 1.0.
Color的默认值设为白色(不透明),理由是:我们将从texture中读取颜色,而不是从多边形的某个角,接着设置不透明的颜色为0xff,但这并不影响texture中本身带有alpha通道。
The color defaults to white (with full opacity) the reason for this is that we will be reading all of our color data from the texture, not from the individual corners of the polygon. Note that although we set the opacity to 0xff, this does not preclude the texture map from using its own alpha mask.
Tu和Tv这2个值用来指定texture的范围,基于0.0和1.0之间。当然,聪明的你是不会漏掉这个的。
The TU and TV values are anchors into the texture map. These values are also valid from 0.0 to 1.0. Usually, you won抰 ever want to mess with these.
现在所有顶点的值都设置好了,然后使用Unlock来释放对这个矩形的锁定,从而得到对应的多边形,为接下来的渲染作准备。
Once all the vertices are set up, you unlock the rectangle to get your polygon ready for rendering.
现在多边形也全部搞定了,如果你要改变这个多边形的顶点缓冲的值(毕竟不是所有的多边形都是全屏的),可以这么做:
Now that the polygon is all set up, suppose you want to alter the vertex locations (after all, not every polygon is going to be full-screen).
void Poly::SetVertRect(int x, int y, int w, int h, float d)
{
float left, top, right, bottom;
left = ((float)x (float)VIEWPORT_WIDTH) * 2.0f - 1.0f;
right = ((float)(x + w) (float)VIEWPORT_WIDTH) * 2.0f - 1.0f;
top = ((float)y (float)VIEWPORT_HEIGHT) * 2.0f - 1.0f;
bottom = ((float)(y + h) (float)VIEWPORT_HEIGHT) * 2.0f - 1.0f;
CUSTOMVERTEX* pVertices;
m_VertexBuffer->Lock( 0, 4*sizeof(CUSTOMVERTEX), (BYTE**)&pVertices, 0);
pVertices[0].position=D3DXVECTOR3( left, bottom, d );
pVertices[1].position=D3DXVECTOR3( right, bottom, d );
pVertices[2].position=D3DXVECTOR3( left, top, d );
pVertices[3].position=D3DXVECTOR3( right, top, d );
m_VertexBuffer->Unlock();
}
这个函数将根据传入的值(x,y,width,height)来生成新的一系列顶点,以改变这个矩形的范围。最后,它通过Lock住这个缓冲以写入改变的值。假如你想将一个sprite从屏幕的右边移动到左边的话,你可以在每一帧里调用SetVertRect(--x,y,width,height,depth)。这段代码根据传入的虚拟坐标值(基于系统的可视范围),来传换成 -1.0至1.0中的有效值。
This function translates a rectangle (x, y, width, height) into correct vertex locations, and alters the vertex buffer accordingly. If, for instance, you were slowly moving a sprite from the right side of the screen to the left you might call SetVertRect(--x, y, width, height, depth) once per frame. This code takes the assumed locations (based on a Viewport_width, Viewport_height coordinate system), and resizes them to the correct -1.0 to 1.0 value. After that, it locks the buffer and writes out the changes.
纹理
class Texture
{
public:
Texture() { Clear(); }
Texture(const char * Filename) { Init(Filename); }
~Texture() { Clear(); }
void Init (const char * Filename);
void Clear();
LPDIRECT3DTEXTURE8 pTexture;
int m_Width;
int m_Height;
int m_Pitch;
};
在Texture对象中,包含了图像数据,并用一成员变量LPDIRECT3DTEXTURE保存它。
The Texture Object holds image-specific data, and the buffer to the actual texture.
void Texture::Init (const char * Filename)
{
TGAFile file;
file.read(Filename);
m_Width=file.m_Width;
m_Height=file.m_Height;
m_Pitch=file.m_Pitch;
MyD3D.m_pd3dDevice->CreateTexture( file.m_Width, file.m_Height, 0, 0,
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture );
D3DLOCKED_RECT d3dlr;
pTexture->LockRect( 0, &d3dlr, 0, 0 );
DWORD * pDst = (DWORD *)d3dlr.pBits;
int DPitch = d3dlr.Pitch4;
DWORD * pSrc = (DWORD *)file.m_PixelData;
int SPitch = file.m_Pitch4;
for (int i=0; i
for (int j=0; j
pDst[i*DPitch + j] = pSrc[i*SPitch + j];
pTexture->UnlockRect (0);
}
上面的例子通过读取一个TGA图像文件的数据来填充texture。呵呵,读取TGA文件在任何时候都不是一件有趣的事情,真正有意思的部分是从调用CreateTexture函数开始。它需要传入Texture的宽、高、图像格式,以及一个指向成功调用后所开辟的缓冲指针:LPDIRECT3DTEXTURE8
In this sample, textures are filled with TGA file data. However, reading TGA files is not the interesting thing about this function. The interesting part starts with the CreateTexture function. This function receives as parameters a width, height, image format, and the type of memory used to allocate the texture. It returns a pointer to the newly created texture.
在成功地获得缓冲的指针后,同样通过Lock来锁定texture缓冲,就像在大多数DirectX 程序那样:锁定某个资源后,通过返回的指针填写数据,最后在所有的工作完成后Unlock资源。
Once the pointer is received, we can lock the rectangle that holds that texture. Again, we follow the standard DirectX pattern of locking a resource, filling the data it points us to, and unlocking the resource.
请注意下面这一段代码:
Consider this section:
for (int i=0; i
for (int j=0; j
pDst[i*DPitch + j] = pSrc[i*SPitch + j];
这里是整个程序的关键之所在。当你操作texture的指针时,可以像过去我们所熟悉的,就像是在操作DirectDraw Surface指针。这个时候,你可以做任何你想做的事情,比方说:绘制 Bresenham直线、画圆或者绘制一个位图(就像这个例子所展示的这样)。在上面的代码中,我们从一个源位图中读取数据,并拷贝到目标位图中去。同样,我们可以指定某种颜色,用来填充目标位图,就像这样:
This is the key to the whole program. While you have access to the texture pointer, you can treat the texture just like a DirectDraw Surface Pointer. You can use this pointer to draw Bresenham lines, circles, or bitmaps (as in this sample case). In this section of code, we copy from a source bitmap to a destination bitmap. However, we could just as easily fill with a specific color:
pDst[y*Dpitch + x] = ( alpha << 24 | red << 16 | green<< 8 | blue )
另外有一点需要注意的是,上面这些函数中,我在使用其中的一些函数时,对于某些参数的具体意义没有去详细地解释它的意义,不过你可以通过查询DX8的SDK中的帮助文件,从而得到更多的信息。例如:在Lock和Unlock函数中,第1个参数是0, 这是因为每个texture(译注:在Mip-mapping的情况下纹理可能包含多个表面,所谓Mip-mapping是指为远处的物体存一个更小的版本的位图Mip-Mapping。在3D中,当物体很远,不需要细节的时候使用最小尺寸的位图。在2D中我们并不关心这个(Mip-Mapping),因此我们将是使用的纹理为单顶层表面,调用0层)都有8个"面",它意味着Lock的是第0个"面",而在2D渲染中,我们只需要使用第0个就可以了。而直到这之前,我都没有像刚才那样把每一件事都说明得很清楚,因为这已经不属于本文的范围,你应该去花时间来熟悉这些函数的使用方法。
One other point, I have glossed over several of the parameters in some of these functions, and it would be well worth the trouble to look them up in the DX8 SDK. For instance, in the Lock and Unlock functions, the first parameter is a 0, which indicates that you are locking the 0th stage identifier. Every surface has up to 8 surfaces, but for 2D rendering we only use the 0th. Since it was not needed for 2D rendering, I didn抰 mention this, however, you may still want to read up on these functions when you are implementing them.
结束语 在这个例子中,我们见到了如何在Direct3D环境下构造我们高性能的2D程序。同样,我们也知道了在不放弃过去所掌握的2D知识的情况下,如何获得DirectX8所带来的好处:更快的Blit、Alpha blending、缩放、还有很多……
In this sample we have seen how to implement Direct3D to perform fast 2D functions. Also, we have seen how we can easily gain important 2D functions (stretching, alpha blending, etc.) without sacrificing our 2D coding knowledge.
下面我给出本文所介绍的程序源码,相比文中所介绍的,它做了很少的一些改动。为了你能更清楚地理解这段程序,我去掉了读取TGA图像文件的部分。你可以从这里下载源代码:dx8adv2d.zip(43K)
There have been some slight changes in the source that is bundled with this text, but the changes are largely cosmetic. I took out the TGA reader to make the code more readable. Download the source code here: dx8adv2d.zip
Brand Gamblin在过去的5年中一直在Microprose Hunt Valley Studio和Kinesoft Austin担任游戏程序员。不过他现在正在找工作(译注:呵呵,跟我一样^^),他还维护着他的个人主页,你可以在这里访问:http://www.niftycode.com。(有空的话,也请访问我的主页^^:http://tlovexyj.yeah.net)
Brand Gamblin has worked as a game programmer for the last five years at Microprose Hunt Valley Studio and Kinesoft Austin. He's now looking for work, and maintaining his own website at http://www.niftycode.com
|
|