旋转 SDL_Surface 不可预测地产生不正确的结果

Rotating SDL_Surface unpredictably produces incorrect result

一直在 c# 中试验 SDL2,并尝试创建一个 maxrects 驱动的纹理打包器。为了以 space 有效的方式打包图集,几乎总是需要旋转纹理。该程序使用 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), IntPtr.Zero, atlas, ref best) < 0)
        throw new Exception(SDL_GetError());
}

这是一种非常不安全的方法,令我惊讶的是,它的工作方式与当前形式一样好,但是它在生成的图集中出现了一个看似不可预测的错误(如果我之前保存旋转的表面,则在单​​独的图像中blitting),只能通过错误转换的图像本身来最好地描述:

Imgur 不保留原始数据,而是在此处 Google 之前和之后的驱动链接:
After rotation (png)

Before rotation (jpg)

请注意,这不仅限于 .jpg 文件,该格式也不一定会导致问题,.png 文件偶尔也会出现同样的情况,但频率较低。如果我要解释发生了什么:图像被轻微压扁,一个扇区被切割并重新定位,并且颜色分裂成几乎 CRT 外观的扫描线效果,似乎以 3 行的模式重复,但仍然在一定程度上反映了原始图像图片,旋转。

有谁知道可能导致这种情况的原因、如何预防这种情况,或者如何以编程方式检测它何时会发生并避免这种情况。或者,如果必须的话,有更好的方法来做这件事吗?我目前找不到关于 formats/dimensions 导致此问题的任何一致性,并且已确认它不是导致问题的 blitting 进程,并且 maxrects 算法按预期工作 - 返回的矩形是有效的。如果你能帮忙,提前谢谢..

正如@kelter 所指出的,我最初应该检查表面格式。如果需要加载图像,通过选择性地转换表面,代码按预期工作。

作为对具体问题的解释,我使用的两种格式的文件恰好是 ABGR8888 和 RGB24,这就是为什么 byteswap 使原始部分起作用的原因,3 的模式是由于 3byte vs 4byte内存布局,导致某些像素被'skipping'挤压,溢出导致最终图像中的额外重复切割。