为了开发一个新项目,Cube Art Project 采用了测试驱动开发方法。在这种方法中,首先实现对应用程序的特定功能的测试,然后再实现该特定功能。我认为这种方法的一大优点是最终接口的实现,在功能开发开始之前尽可能不涉及实现细节。通过这种方法,当接口是特定实现的契约时,测试指示进一步的实现,添加契约编程的所有好处。
立方体艺术项目–一种 3D 编辑器,用户可以在其中从立方体构建图形;不久前,这种类型非常流行。由于这是一个图形应用程序,我决定添加带有屏幕截图验证的测试。
要验证屏幕截图,您需要从 OpenGL 上下文中获取它们,这是使用 glReadPixels 函数完成的。函数参数的描述很简单–起始位置、宽度、高度、格式(RGB/RGBA/等)、指向输出缓冲区的指针;任何使用过 SDL 或具有 C 数据缓冲区经验的人都可以简单地替换必要的参数。然而,我认为有必要描述一下 glReadPixels 输出缓冲区的一个有趣的功能;像素从下到上存储在其中,而在 SDL_Surface 中,所有基本操作都是从上到下发生的。
也就是说,从 png 文件加载参考屏幕截图后,我无法直接比较两个缓冲区,因为其中一个缓冲区是颠倒的。
要从 OpenGL 翻转输出缓冲区,您需要通过减去 Y 坐标的屏幕截图高度来填充它。但是,值得考虑的是,如果在填充时不减去它,则有可能超出缓冲区限制。导致内存损坏。
由于我总是尝试使用“通过接口编程”的 OOP 范例,而不是通过指针直接进行类似 C 的内存访问,因此当我尝试在缓冲区外部写入数据时,由于方法中的边界验证,对象会通知我这一点.
自上而下的截图方法最终代码:
auto width = params->width;
auto height = params->height;
auto colorComponentsCount = 3;
GLubyte *bytes = (GLubyte *)malloc(colorComponentsCount * width * height);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, bytes);
auto screenshot = make_shared(width, height);
for (auto y = 0; y < height; y++) {
for (auto x = 0; x < width; x++) {
auto byteX = x * colorComponentsCount;
auto byteIndex = byteX + (y * (width * colorComponentsCount));
auto redColorByte = bytes[byteIndex];
auto greenColorByte = bytes[byteIndex + 1];
auto blueColorByte = bytes[byteIndex + 2];
auto color = make_shared(redColorByte, greenColorByte, blueColorByte, 255);
screenshot->setColorAtXY(color, x, height - y - 1);
}
}
free(bytes);
来源
https://community.khronos.org/ t/glreadpixels-fliped-image/26561
https://stackoverflow.com/questions/8346115/why-are-bmps-stored-upside-down
源代码
https://gitlab.com/demensdeum/cube-艺术项目引导