问题描述
已经在c#中试验了SDL2,并试图创建一个maxrects驱动的纹理打包器。为了使地图集以节省空间的方式包装,几乎总是需要旋转纹理。该程序使用SDL_Surfaces从文件中加载图像,并将其blit到更大的SDL_Surface中并将其写入磁盘。这就是我实施轮换的方式:
// get pointer to original SDL_Surface
var sptr = (SDL_Surface*)surfaces[bestIndex].Item2;
// check if maxrects algorithm has rotated the rectangle "best"
if (best.w != sptr->w) {
var rotd = (SDL_Surface*)SDL_CreateRGBSurfaceWithFormat(0,sptr->h,sptr->w,32,SDL_PIXELFORMAT_RGBA8888);
IntPtr rotdPixels = rotd->pixels;
IntPtr sptrPixels = sptr->pixels;
for (int y = 0; y < sptr->h; y++) {
for (int x = 0; x < sptr->w; x++) {
// get target pointer by swapping dimensions and flipping one,resulting in a rotation
uint* target = (uint*)(rotdPixels + x * rotd->pitch + (sptr->h - y - 1) * 4);
// set target from the expected location. Bswsp is necessary.
*target = System.Buffers.Binary.BinaryPrimitives.ReverseEndianness(*(uint*)(sptrPixels + y * sptr->pitch + x * 4));
}
}
if (SDL_BlitSurface(new IntPtr(rotd),IntPtr.Zero,atlas,ref best) < 0)
throw new Exception(SDL_GetError());
} else {
if (SDL_BlitSurface(new IntPtr(sptr),ref best) < 0)
throw new Exception(SDL_GetError());
}
这是一种非常不安全的方法,令我惊讶的是它的工作方式以及它在当前形式下的表现都很好,但是它在生成的图集中显示了看似不可预测的错误(如果在发条前保存旋转的曲面,则在单独的图像中显示) ,这只能由变形后的图片本身来最好地描述:
Imgur不会保留原始数据,而是在这里Google Drive链接到之前和之后的内容:
After rotation (png)
请注意,这不仅限于.jpg文件,也不一定会导致这种问题,.png文件偶尔也会执行相同的操作,但次数较少。如果我要解释发生了什么:图像被稍微压扁,一个扇区被切割并重新定位,并且颜色分裂成看起来几乎像CRT的扫描线效果,似乎以3行的图案重复出现,但是仍然有点反映了原始图像。图片,旋转。
是否有人知道这可能是什么原因,如何防止它,或者如何以编程方式检测何时会发生并避免它。或者,如果必须这样做,那么是执行此操作的更好方法?我目前无法找到导致此问题的格式/尺寸的一致性,并已确认这不是导致该问题的blitting流程,并且maxrects算法正在按预期工作-返回的矩形有效。如果可以的话,请先谢谢。
解决方法
正如@kelter指出的那样,我最初应该已经检查了表面格式。通过在需要加载图像时选择性地转换表面,代码按预期工作。
为解释特殊的奇怪情况,我使用的两种文件格式分别为ABGR8888和RGB24,这就是为什么字节交换使原始文件部分起作用的原因,3的模式是由于3byte vs 4byte内存布局,通过在某些像素上“跳过”来引起挤压,并且溢出导致最终图像中多余的重复裁切。