赞 | 2 |
VIP | 143 |
好人卡 | 1 |
积分 | 1 |
经验 | 216792 |
最后登录 | 2019-10-10 |
在线时间 | 24 小时 |
Lv1.梦旅人
- 梦石
- 0
- 星屑
- 61
- 在线时间
- 24 小时
- 注册时间
- 2008-8-5
- 帖子
- 1924
|
本帖最后由 紫苏 于 2009-7-24 13:56 编辑
原来的 bitmap_data 方法写得乱七八糟的,我给改了一下,试试看还有没有问题?- class << Graphics
- GetDC = Win32API.new("user32", "GetDC", 'L', 'L')
- CreateCompatibleBitmap = Win32API.new("gdi32", "CreateCompatibleBitmap", "lll", "l")
- CreateCompatibleDC = Win32API.new("gdi32", "CreateCompatibleDC", "l", "l")
- SelectObject = Win32API.new("gdi32", "SelectObject", "ll", "l")
- BitBlt = Win32API.new("gdi32", "BitBlt", "lllllllll", "l")
- GetBitmapBits = Win32API.new("gdi32", "GetBitmapBits", "llp", "l")
- ReleaseDC = Win32API.new("user32", "ReleaseDC", "LL", 'L')
- DeleteDC = Win32API.new("gdi32", "DeleteDC", "l", "l")
- DeleteObject = Win32API.new("gdi32", "DeleteObject", "l", "l")
- SRCCOPY = 0xCC0020
- RtlMoveMemory = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
- HWnd = Win32API.new("user32", "GetActiveWindow", nil, 'l').call
- DwCount = 640 * 480 * 4
- @@lpBits = "\000" * DwCount
- #--------------------------------------------------------------------------
- # ● snap_to_bitmap
- # 将当前画面转换为Bitmap对象
- #--------------------------------------------------------------------------
- def snap_to_bitmap
- width, height = 640, 480
- hb = Bitmap.new(width, height)
- rgbs = self.bitmap_data
- len = width * 4
- for y in 0...height
- break if 2 * y >= height - 1
- nth1 = y * len
- nth2 = (height - 1 - y) * len
- tStr = rgbs[nth1,len]
- rgbs[nth1, len] = rgbs[nth2, len]
- rgbs[nth2, len] = tStr
- end
- RtlMoveMemory.call(hb.address, rgbs, 640 * 480 << 2)
- return hb
- end
- #--------------------------------------------------------------------------
- # ● bitmap_data
- # 获取当前画面的数据部分```
- # RGB依然是调转过来了`= =``
- #--------------------------------------------------------------------------
- def bitmap_data
- hScrDC = GetDC.call(HWnd)
- hMemDC = CreateCompatibleDC.call(hScrDC)
- hBitmap = CreateCompatibleBitmap.call(hScrDC, 640, 480)
- SelectObject.call(hMemDC, hBitmap)
- BitBlt.call(hMemDC, 0, 0, 640, 480, hScrDC, 0, 0, SRCCOPY)
- GetBitmapBits.call(hBitmap, DwCount, @@lpBits)
- DeleteObject.call(hBitmap)
- DeleteDC.call(hMemDC)
- ReleaseDC.call(HWnd, hScrDC)
- return @@lpBits
- end
- end
复制代码 原来的 bitmap_data 很诡异地去创建了一个屏幕 DC,然后通过诡异的超大内存(那个宽 640 * 2,高 480 * 2 的地方实在莫名其妙) DC 把屏幕 DC 的 RM 窗口客户区矩形位图复制了过去,实际上截取窗口客户区根本不需要这么麻烦——
直接用 GetDC 获取客户区 DC,然后通过 CreateCompatibleDC 和
CreateCompatibleBitmap 创建兼容 DC 和兼容位图,也就是创建了一个绘图的缓存(绘图缓存在游戏中是必不可少的,所有的绘制先要在缓存中完成,然后再一举拷贝到客户区 DC 上,这就是所谓的双缓存技术),然后把客户区的位图拷贝到这个缓存中,最后通过 GetBitmapBits 就获取到了位图的数据(宽*高*4 的数组,4是因为在内存中一个像素占四个字节,即 BGRA 四个通道)
位图的数据有了,接下来就是要想办法把数据转换成 RM 的 Bitmap 对象~Bitmap 的 address 方法就是通过 [[[Bitmap#object_id * 2 + 16] + 8] + 16] 的算法获取了 Bitmap 对象的内存首地址(详见柳之一的 Bitmap 序列化贴),这样我们就可以直接修改对象的内存了
最后是 Graphics.snap_to_bitmap 方法,它首先创建了一个 Bitmap 对象,然后截图并获取了窗口快照的数据~由于位图的像素数据是按照从下到上,从左到右的顺序排列的,而 RM 的 Bitmap 对象却是从上到下,从左到右,所以这两者的扫描行位置是相反的,位图数据的第一行其实应该是 Bitmap 对象的最后一行,位图数据的第二行应该是 Bitmap 对象的倒数第二行,以此类推~所以 snap_to_bitmap 就做了相应的行交换,交换完毕之后把数据拷贝到对象所在的内存地址,这样一来我们需要的 Bitmap 对象就创建成功了 |
|