DirectXGraphics访问贴图内存

Jack Hoxley译:zh1110

1.介绍
2. 贴图到贴图的拷贝
3. 快速访问贴图内存
4. 快速访问背景缓冲及前缓冲
5.内存中的操作

1. 介绍

也许你想将一些小的贴图组合成一张大的贴图,也许你想通过数学方法创建贴图(如羽化),也许你想将一张世界地图通过一定接口到贴图上。。。这些方法是我们将介绍的.

2. 贴图到贴图的拷贝

很典型的应用是一些小图形的平铺(草坪,石头,水)。

Direct3D 只允许在surfaces (Direct3DSurface8)间拷贝 , not textures (Direct3DTexture8) - 所以首先要转化成一个surface. 本质上我们并不是转化或拷贝他们到 surfaces, 我们是造了一个输入点, 相当于C/C++ 中的指针(如果你了解它)surface的改变会反映到textures 上,这样我们渲染就有了修改的目标. 下面是全部代码:

'## 声明DECLARATIONS ##
                                                            '//Our renderable textures 我们渲染的贴图
                                                            Dim TexSource As Direct3DTexture8
                                                            Dim TexDest As Direct3DTexture8
                                                            Dim TexComb As Direct3DTexture8
                                                            '//The surfaces that will point to them.它们的指针
                                                            Dim SurfSource As Direct3DSurface8
                                                            Dim SurfDest As Direct3DSurface8
                                                            Dim SurfComb As Direct3DSurface8
                                                            '## 初始INITIALISATION ##
                                                            '//Create Our TEXTURE objects创建我们的TEXTURE对象
                                                            Set TexSource = D3DX.CreateTextureFromFileEx(D3DDevice, App.Path & "\texsource.bmp", _
                                                            128, 128, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, _
                                                            D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, ByVal 0, _
                                                            ByVal 0)
                                                            Set TexDest = D3DX.CreateTextureFromFileEx(D3DDevice, App.Path & "\texdest.bmp", _
                                                            128, 128, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, _
                                                            D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, ByVal 0, _
                                                            ByVal 0)
                                                            Set TexComb = D3DX.CreateTexture(D3DDevice, 128, 128, 1, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED)
                                                            '## 渲染循环RENDER LOOP ##
                                                            '//渲染时创建一个texture指针
                                                            Set SurfSource = TexSource.GetSurfaceLevel(0)
                                                            Set SurfDest = TexDest.GetSurfaceLevel(0)
                                                            Set SurfComb = TexComb.GetSurfaceLevel(0)
                                                            '我们拷贝1/2SurfSource面及1/2 SurfDest面到SurfComb
                                                            rctSource.Top = 0: rctSource.Left = 0: rctSource.Right = 64: rctSource.bottom = 128
                                                            ptDest.X = 0: ptDest.Y = 0
                                                            D3DDevice.CopyRects SurfSource, rctSource, 1, SurfComb, ptDest
                                                            rctSource.Top = 0: rctSource.Left = 64: rctSource.Right = 128: rctSource.bottom = 128
                                                            ptDest.X = 64: ptDest.Y = 0
                                                            D3DDevice.CopyRects SurfDest, rctSource, 1, SurfComb, ptDest


我使用CreateTextureFromFileEx( ) - 这样可以指定特别的贴图类型。我们还可指定 D3D的Mip Mapping ,我们用主贴图所以我们输入0。

最后用 CopyRects( ) 函数.特别要说明的是rectangles区域不能超过贴图边缘,否则 D3D会拒绝,它也不同于coordinates的尺寸 0.0 to 1.0 scale...


3. 快速访问贴图内存

它可以产生一些特殊效果(Alpha Blending, Colour Blending, Particle Effects, Lighting etc...),一些复杂程序也用到,此外你还可以自定义你的图片格式...

Dim pData As D3DLOCKED_RECT, pxArr() As Byte
                                                            TexDMA.LockRect 0, pData, ByVal 0, 0
                                                                    '我们现在可以访问 stuff 利用 pData
                                                            ReDim pxArr(pData.Pitch * 128) As Byte '所有 bytes类型就足够了,其他如integers or longs浪费
                                                            DXCopyMemory pxArr(0), pData.pBits, pData.Pitch * 128 '  surface高度为128
                                                            DXCopyMemory ByVal pData.pBits, pxArr(0), pData.Pitch * 128 'pxArr() 包含了 texture's 每一点的数据
                                                            TexDMA.UnlockRect 0


vb本身不支持指针所以我们用 DXCopyMemory( ) (它包含了API 函数CopyMemory )....

4. 快速访问背景缓冲及前景缓冲

这其实是前面所讲的延伸.

Dim FrontBuffer As Direct3DSurface8
                                                            Dim BackBuffer As Direct3DSurface8
                                                            D3DDevice.GetFrontBuffer FrontBuffer
                                                            Set BackBuffer = D3DDevice.GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO)
                                                            'you can now lock as per normal:
                                                            FrontBuffer.LockRect pData, rct, 0
                                                            BackBuffer.LockRect pData, rct, 0
                                                            'etc...


5.内存中的操作

什么是象数格式? 8 bit, 16 bit, 24 bit and 32 bit 是基本的格式, 它告诉你每点存储多少 bits 内存。如标志"D3DFMT_X8R8G8B8" and "D3DFMT_R5G6B5" (在 CreateTextureFromFileEx( ) 函数中)。8 bits = 1 byte.

TexDMA2.LockRect 0, pData, ByVal 0, 0
                                                                '我们现在可以访问 stuffpData
                                                                ReDim pxArr(pData.Pitch * 128) As Byte
                                                                If Not (DXCopyMemory(pxArr(0), ByVal pData.pBits, pData.Pitch * 128) = D3D_OK) Then
                                                                    '发生错误时的语句
                                                                End If
                                                                ' XRGB 格式...
                                                                For x = 0 To (pData.Pitch * 128) - 1 Step 4
                                                                    'unused = pxArr(x + 3)
                                                                    bRed = pxArr(x + 2)
                                                            bGreen = pxArr(x + 1)
                                                            bBlue = pxArr(x + 0)
                                                            bRed = 0
                                                            bGreen = 0
                                                            bBlue = 255
                                                            pxArr(x + 2) = bRed
                                                            pxArr(x + 1) = bGreen
                                                            pxArr(x + 0) = bBlue
                                                            Next x
                                                            If Not (DXCopyMemory(ByVal pData.pBits, pxArr(0), pData.Pitch * 128) = D3D_OK) Then
                                                                    '拷贝发生错误时的语句
                                                                End If
                                                            TexDMA2.UnlockRect 0


 original array 存储数据,排序为BGRXBGRXBGRXBGRXBGRX 所以我们在主循环用 "Step 4" ,我们同时要正确使用X/Ycoordinates .

 

16位格式的排序:[RRRRRGGG] [GGGBBBBB] (where [] signifies a byte)

16位下提取颜色的过程如下:

1. Take the two bytes, combine them into one straight 16 bit line
2. Mask out the green and blue channels, shift right 11 bits = Red
3. Mask out the red and blue channels, shift right 5 bits = Green
4. Mask out the red and green channels = Blue
- Manipulate colours here -
5. Shift the Red left by 11 bits, shift the green across by 5 bits
6. Combine the Red, Green and Blue values into a 16 bit long
7. Mask out the lowest 8 bits, shift right 8 bits = second byte
8. Mask out the highest 8 bits = first byte.


Step 1:
组合

bFirst = pxArr(x)
                                                            bSecond = pxArr(x + 1)
                                                            lRes = (bSecond * 2 ^ 8) Or bFirst


OR 操作真值表:

A
B
A Or B
0
0
0
1
0
1
0
1
1
1
1
1

1111111100000000 = bSecond shifted left 8 bits
0000000011111111 = bFirst
---------------------
1111111111111111 = lRes

Step 2: 提取红色部分
And操作真值表

A
B
A And B
0
0
0
1
0
0
0
1
0
1
1
1

1011011101100111 = 16 bit chain
1111100000000000 = Red mask, 63488
---------------------
1011000000000000 = output, red shifted left by 11 bits
0000000000010110 = Red correctly shifted right by 11 bits.

bRed = (lRes And 63488) / 2 ^ 11
                                                            bRed = (255 / 31) * bRed 'to convert to the familiar 0-255 range.

Step 3: 提取绿色部分

bGreen = (lRes And 2016) / 2 ^ 5
                                                            bGreen = (255 / 63) * bGreen 'to convert it to 0-255 range


Again, we convert it to the 0-255 range.

Step 4: 提取蓝色部分

bBlue = lRes And 31
bBlue = (255 / 31) * bBlue 'convert it to 0-255 range


Step 5 & 6: 再次处理

'//Convert RED
                                                                bRed = Int((31 / 255) * bRed) 'convert it back to the 0-31 scale
                                                                lRed = bRed * 2 ^ 11
                                                            '//Convert GREEN
                                                                bGreen = Int((63 / 255) * bGreen) 'convert it back to the 0-63 scale
                                                                lGreen = bGreen * 2 ^ 5
                                                            '//Convert BLUE
                                                                bBlue = Int((31 / 255) * bBlue) 'convert back to the 0-31 scale
                                                                lBlue = bBlue
                                                            '//Assemble Complete Long
                                                                lRes = lRed Or lGreen Or lBlue

 

'bSecond is the highest 8 bits
bSecond = (lRes And 65280) / 2 ^ 8
'bfirst is the lowest 8 bits
bFirst = lRes And 255

pxArr(x) = bFirst
pxArr(x + 1) = bSecond