如何计算网格缩放后一维像素缓冲区的行主序索引?
解决Rust+minifb生命游戏中像素缓冲区索引计算问题
minifb的update_with_buffer要求的一维缓冲区是行优先存储——也就是先按顺序存完屏幕第一行的所有像素,再存第二行,以此类推。要正确计算每个放大后像素的索引,得先明确每个网格单元对应屏幕上的位置,再套用行优先的索引公式。
正确的索引计算逻辑
- 原网格中坐标为
(y, x)的单元格,放大后对应屏幕上一个horiz_scale × vert_scale的方块:- 方块左上角的屏幕X坐标:
x * horiz_scale - 方块左上角的屏幕Y坐标:
y * vert_scale
- 方块左上角的屏幕X坐标:
- 方块内的偏移量
px(水平方向,0到horiz_scale-1)和py(垂直方向,0到vert_scale-1),对应屏幕上的实际坐标:- 实际屏幕X:
x * horiz_scale + px - 实际屏幕Y:
y * vert_scale + py
- 实际屏幕X:
- 行优先的索引公式:
实际屏幕Y × 屏幕总宽度 + 实际屏幕X,其中屏幕总宽度是cols * horiz_scale(列数×水平缩放比例)。
修正后的代码
// 先计算屏幕总宽度,避免重复计算 let screen_width = cols * horiz_scale; // 确保缓冲区长度是 screen_width * (rows * vert_scale),否则会索引越界 for y in 0..rows { for x in 0..cols { let color = if grid[y][x] == 1 { 0xFFFFFF } else { 0x000000 }; for py in 0..vert_scale { for px in 0..horiz_scale { // 正确的索引计算 let pixel_id = (y * vert_scale + py) * screen_width + (x * horiz_scale + px); buffer[pixel_id] = color; } } } }
分析你之前的错误写法
- 能生成方块但逻辑错误的写法:
y * cols as usize * horiz_scale + x * vert_scale * rows + px * py
这里x * vert_scale * rows完全混淆了行和列的缩放关系,px * py也不是正确的偏移计算,只是碰巧能渲染出方块,但网格的位置、缩放比例肯定不符合预期。 - 导致闪烁的写法:
x * rows as usize * vert_scale * horiz_scale + y * vert_scale * horiz_scale + px * vert_scale + py
这个公式把x作为行维度计算,相当于把图像旋转了90度,而且大概率会计算出超出缓冲区范围的索引,触发内存越界,进而导致窗口闪烁、显示乱码。 - 接近正确的写法:
((y * vert_scale + py) * (cols as usize * horiz_scale)+ x * horiz_scale+ px) as usize
这个公式本身是对的,如果还是有问题,检查两点:- 缓冲区的长度是否等于
rows * vert_scale * cols * horiz_scale rows、cols的类型是否为usize(避免整数溢出或类型转换错误)
- 缓冲区的长度是否等于
内容的提问来源于stack exchange,提问作者Daselsdis
相关产品推荐
相关产品推荐

