在哪里可以找到关于实现用于计算“脏矩形”的算法的参考文献,以最小化帧缓冲区更新?一种显示模型,允许任意编辑并计算更新显示所需的最小“位blit”操作集。
答案 0 :(得分:3)
构建包含需要重新绘制的所有区域的最小矩形:
对于每个添加的脏区:
Windows至少维护了一个更新区域,其中包含已被通知的更改,以及由于窗口被遮盖和显示而需要进行的任何重新绘制。 区域是一个由许多可能不连续的矩形,多边形和椭圆组成的对象。您通过调用InvalidateRect告诉Windows需要重新绘制的部分屏幕 - 对于更复杂的区域,还有一个InvalidateRgn函数。如果您选择在下一个WM_PAINT消息到达之前进行一些绘制,并且您希望将其从脏区域中排除,则可以使用ValidateRect和ValidateRgn函数。
当您开始使用BeginPaint绘画时,您提供了一个PAINTSTRUCT,Windows填充了有关需要绘制内容的信息。其中一个成员是包含无效区域的最小矩形。你可以使用GetUpdateRgn获取区域本身(你必须在BeginPaint之前调用它,因为BeginPaint将整个窗口标记为有效)如果你想在有多个小的无效区域时最小化绘图。
我认为,在最初编写这些环境时,最小化绘图在Mac和X上很重要,因此维护更新区域的机制相同。
答案 1 :(得分:3)
听起来你需要的是你要渲染到屏幕的每个形状的边界框。请记住,多边形的边界框可以定义为“左下”(最小点)和“右上角”(最大点)。也就是说,最小点的x分量被定义为多边形中每个点的所有x分量的最小值。对y分量(在2D的情况下)和边界框的最大点使用相同的方法。
如果每个多边形有一个边界框(也就是“脏矩形”)就足够了,你就完成了。如果您需要一个整体复合边界框,则应用相同的算法,除了您可以使用最小和最大点填充单个框。
现在,如果您在Java中执行所有操作,则可以使用getBound2D()
method直接获取Area
(可以从任何Shape
构建)的边界框。
答案 2 :(得分:3)
Vexi是对此的参考实现。该类为org.vexi.util.DirtyList(Apache许可证),用作生产系统的一部分,即经过全面测试,并且评论很好。
需要注意的是,当前的类描述有点不准确,“用于保存需要重新绘制的矩形区域列表的通用数据结构,具有智能合并功能。”实际上它确实如此目前没有合并。因此,您可以将此视为一个基本的DirtyList实现,因为它只与dirty()请求相交,以确保没有重叠的脏区。
该实现的一个细微差别在于,不是使用Rect或其他类似的区域对象,而是将区域存储在一个int数组中,即在一维数组中以4个int的块存储。这是为了提高运行时效率,尽管回想起来我不确定它是否有很多优点。 (是的,我实现了它。)将Rect替换为正在使用的数组块应该很简单。
该课程的目的是快速。对于Vexi,每帧可能会调用脏数千次,因此脏区域与脏请求的交叉必须尽可能快。不超过4个数字比较用于确定两个区域的相对位置。
由于缺少合并,它并不完全是最佳的。虽然它确实确保脏/涂区域之间没有重叠,但最终可能会出现排列的区域,并且可能会合并到更大的区域中 - 从而减少绘制调用的数量。
代码段。完整代码online here。
public class DirtyList {
/** The dirty regions (each one is an int[4]). */
private int[] dirties = new int[10 * 4]; // gets grown dynamically
/** The number of dirty regions */
private int numdirties = 0;
...
/**
* Pseudonym for running a new dirty() request against the entire dirties list
* (x,y) represents the topleft coordinate and (w,h) the bottomright coordinate
*/
public final void dirty(int x, int y, int w, int h) { dirty(x, y, w, h, 0); }
/**
* Add a new rectangle to the dirty list; returns false if the
* region fell completely within an existing rectangle or set of
* rectangles (i.e. did not expand the dirty area)
*/
private void dirty(int x, int y, int w, int h, int ind) {
int _n;
if (w<x || h<y) {
return;
}
for (int i=ind; i<numdirties; i++) {
_n = 4*i;
// invalid dirties are marked with x=-1
if (dirties[_n]<0) {
continue;
}
int _x = dirties[_n];
int _y = dirties[_n+1];
int _w = dirties[_n+2];
int _h = dirties[_n+3];
if (x >= _w || y >= _h || w <= _x || h <= _y) {
// new region is outside of existing region
continue;
}
if (x < _x) {
// new region starts to the left of existing region
if (y < _y) {
// new region overlaps at least the top-left corner of existing region
if (w > _w) {
// new region overlaps entire width of existing region
if (h > _h) {
// new region contains existing region
dirties[_n] = -1;
continue;
}// else {
// new region contains top of existing region
dirties[_n+1] = h;
continue;
} else {
// new region overlaps to the left of existing region
if (h > _h) {
// new region contains left of existing region
dirties[_n] = w;
continue;
}// else {
// new region overlaps top-left corner of existing region
dirty(x, y, w, _y, i+1);
dirty(x, _y, _x, h, i+1);
return;
}
} else {
// new region starts within the vertical range of existing region
if (w > _w) {
// new region horizontally overlaps existing region
if (h > _h) {
// new region contains bottom of existing region
dirties[_n+3] = y;
continue;
}// else {
// new region overlaps to the left and right of existing region
dirty(x, y, _x, h, i+1);
dirty(_w, y, w, h, i+1);
return;
} else {
// new region ends within horizontal range of existing region
if (h > _h) {
// new region overlaps bottom-left corner of existing region
dirty(x, y, _x, h, i+1);
dirty(_x, _h, w, h, i+1);
return;
}// else {
// existing region contains right part of new region
w = _x;
continue;
}
}
} else {
// new region starts within the horizontal range of existing region
if (y < _y) {
// new region starts above existing region
if (w > _w) {
// new region overlaps at least top-right of existing region
if (h > _h) {
// new region contains the right of existing region
dirties[_n+2] = x;
continue;
}// else {
// new region overlaps top-right of existing region
dirty(x, y, w, _y, i+1);
dirty(_w, _y, w, h, i+1);
return;
} else {
// new region is horizontally contained within existing region
if (h > _h) {
// new region overlaps to the above and below of existing region
dirty(x, y, w, _y, i+1);
dirty(x, _h, w, h, i+1);
return;
}// else {
// existing region contains bottom part of new region
h = _y;
continue;
}
} else {
// new region starts within existing region
if (w > _w) {
// new region overlaps at least to the right of existing region
if (h > _h) {
// new region overlaps bottom-right corner of existing region
dirty(x, _h, w, h, i+1);
dirty(_w, y, w, _h, i+1);
return;
}// else {
// existing region contains left part of new region
x = _w;
continue;
} else {
// new region is horizontally contained within existing region
if (h > _h) {
// existing region contains top part of new region
y = _h;
continue;
}// else {
// new region is contained within existing region
return;
}
}
}
}
// region is valid; store it for rendering
_n = numdirties*4;
size(_n);
dirties[_n] = x;
dirties[_n+1] = y;
dirties[_n+2] = w;
dirties[_n+3] = h;
numdirties++;
}
...
}
答案 3 :(得分:2)
您使用的是哪种语言?在Python中,Pygame可以为您完成此任务。使用RenderUpdates组和一些带有image和rect属性的Sprite对象。
例如:
#!/usr/bin/env python
import pygame
class DirtyRectSprite(pygame.sprite.Sprite):
"""Sprite with image and rect attributes."""
def __init__(self, some_image, *groups):
pygame.sprite.Sprite.__init__(self, *groups)
self.image = pygame.image.load(some_image).convert()
self.rect = self.image.get_rect()
def update(self):
pass #do something here
def main():
screen = pygame.display.set_mode((640, 480))
background = pygame.image.load(open("some_bg_image.png")).convert()
render_group = pygame.sprite.RenderUpdates()
dirty_rect_sprite = DirtyRectSprite(open("some_image.png"))
render_group.add(dirty_rect_sprite)
while True:
dirty_rect_sprite.update()
render_group.clear(screen, background)
pygame.display.update(render_group.draw(screen))
如果您没有使用Python + Pygame,我会这样做:
答案 4 :(得分:2)
我刚刚写了一个Delphi类来计算两个图像的差异矩形,并且对它的运行速度感到非常惊讶 - 足够快以在短计时器中运行以及在用于记录屏幕活动的鼠标/键盘消息之后。
它如何运作的一步一步要点是:
通过矩形将图像细分为逻辑12x12。
循环遍历每个像素,如果存在差异,那么我告诉像素所属的子矩形,其中一个像素与其中的区别有差异。
每个子矩形都会记住它自己最左边,最顶部,最右边和最底部差异的坐标。
一旦找到所有差异,我会遍历所有有差异的子矩形,如果它们彼此相邻则形成更大的矩形并使用最左边的,最顶部的,这些子矩形的最右边和最底部差异,以制作我使用的实际差异矩形。
这对我来说似乎很有效。如果您还没有实现自己的解决方案,请告诉我,如果您愿意,我会通过电子邮件发送给您我的代码。截至目前,我是StackOverflow的新用户,所以如果你欣赏我的答案,请投票。 :)
答案 5 :(得分:2)