我们希望通过使用SDL_Image加载图像来创建SDL表面,如果尺寸超过限制,则调整表面大小。
我们需要这样做的原因是在Raspbian SDL上抛出一个从表面创建纹理的错误('纹理尺寸限制为2048x2048 ')。虽然这是一个非常大的图像,但我们不希望用户关注图像大小,我们希望为它们调整大小。虽然我们没有在Windows上遇到这个限制,但我们正试图在Windows上开发解决方案,并且在调整纹理大小时会出现问题。
寻找解决方案有类似的问题......:
当前SDL2是否需要自定义阻击器或SDL_gfx(这些答案早于SDL2 2013发布日期)? SDLRenderCopyEx没有帮助,因为您需要生成出现问题的纹理。
所以我们尝试了一些可用的blitting函数,比如SDL_BlitScaled,下面是一个简单的程序来渲染一个没有缩放的2500x2500 PNG:
#include <SDL.h>
#include <SDL_image.h>
#include <sstream>
#include <string>
SDL_Texture * get_texture(
SDL_Renderer * pRenderer,
std::string image_filename) {
SDL_Texture * result = NULL;
SDL_Surface * pSurface = IMG_Load(image_filename.c_str());
if (pSurface == NULL) {
printf("Error image load: %s\n", IMG_GetError());
}
else {
SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
if (pTexture == NULL) {
printf("Error image load: %s\n", SDL_GetError());
}
else {
SDL_SetTextureBlendMode(
pTexture,
SDL_BLENDMODE_BLEND);
result = pTexture;
}
SDL_FreeSurface(pSurface);
pSurface = NULL;
}
return result;
}
int main(int argc, char* args[]) {
SDL_Window * pWindow = NULL;
SDL_Renderer * pRenderer = NULL;
// set up
SDL_Init(SDL_INIT_VIDEO);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
SDL_Rect screenDimensions;
screenDimensions.x = 0;
screenDimensions.y = 0;
screenDimensions.w = 640;
screenDimensions.h = 480;
pWindow = SDL_CreateWindow("Resize Test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
screenDimensions.w,
screenDimensions.h,
SDL_WINDOW_SHOWN);
pRenderer = SDL_CreateRenderer(pWindow,
-1,
SDL_RENDERER_ACCELERATED);
IMG_Init(IMG_INIT_PNG);
// render
SDL_SetRenderDrawColor(
pRenderer,
0,
0,
0,
0);
SDL_RenderClear(pRenderer);
SDL_Texture * pTexture = get_texture(
pRenderer,
"2500x2500.png");
if (pTexture != NULL) {
SDL_RenderCopy(
pRenderer,
pTexture,
NULL,
&screenDimensions);
SDL_DestroyTexture(pTexture);
pTexture = NULL;
}
SDL_RenderPresent(pRenderer);
// wait for quit
bool quit = false;
while (!quit)
{
// poll input for quit
SDL_Event inputEvent;
while (SDL_PollEvent(&inputEvent) != 0) {
if ((inputEvent.type == SDL_KEYDOWN) &&
(inputEvent.key.keysym.sym == 113)) {
quit = true;
}
}
}
IMG_Quit();
SDL_DestroyRenderer(pRenderer);
pRenderer = NULL;
SDL_DestroyWindow(pWindow);
pWindow = NULL;
return 0;
}
更改get_texture函数以识别限制并尝试创建新曲面:
SDL_Texture * get_texture(
SDL_Renderer * pRenderer,
std::string image_filename) {
SDL_Texture * result = NULL;
SDL_Surface * pSurface = IMG_Load(image_filename.c_str());
if (pSurface == NULL) {
printf("Error image load: %s\n", IMG_GetError());
}
else {
const int limit = 1024;
int width = pSurface->w;
int height = pSurface->h;
if ((width > limit) ||
(height > limit)) {
SDL_Rect sourceDimensions;
sourceDimensions.x = 0;
sourceDimensions.y = 0;
sourceDimensions.w = width;
sourceDimensions.h = height;
float scale = (float)limit / (float)width;
float scaleH = (float)limit / (float)height;
if (scaleH < scale) {
scale = scaleH;
}
SDL_Rect targetDimensions;
targetDimensions.x = 0;
targetDimensions.y = 0;
targetDimensions.w = (int)(width * scale);
targetDimensions.h = (int)(height * scale);
SDL_Surface *pScaleSurface = SDL_CreateRGBSurface(
pSurface->flags,
targetDimensions.w,
targetDimensions.h,
pSurface->format->BitsPerPixel,
pSurface->format->Rmask,
pSurface->format->Gmask,
pSurface->format->Bmask,
pSurface->format->Amask);
if (SDL_BlitScaled(pSurface, NULL, pScaleSurface, &targetDimensions) < 0) {
printf("Error did not scale surface: %s\n", SDL_GetError());
SDL_FreeSurface(pScaleSurface);
pScaleSurface = NULL;
}
else {
SDL_FreeSurface(pSurface);
pSurface = pScaleSurface;
width = pSurface->w;
height = pSurface->h;
}
}
SDL_Texture * pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
if (pTexture == NULL) {
printf("Error image load: %s\n", SDL_GetError());
}
else {
SDL_SetTextureBlendMode(
pTexture,
SDL_BLENDMODE_BLEND);
result = pTexture;
}
SDL_FreeSurface(pSurface);
pSurface = NULL;
}
return result;
}
SDL_BlitScaled失败并显示错误'不支持Blit组合'其他变体也有类似的错误:
SDL_BlitScaled(pSurface, NULL, pScaleSurface, NULL)
SDL_BlitScaled(pSurface, &sourceDimensions, pScaleSurface, &targetDimensions)
SDL_LowerBlitScaled(pSurface, &sourceDimensions, pScaleSurface, &targetDimensions) // from the wiki this is the call SDL_BlitScaled makes internally
然后我们尝试了一个非缩放的blit ...它没有抛出错误但只显示白色(不是图像中的清晰颜色或颜色)。
SDL_BlitSurface(pSurface, &targetDimensions, pScaleSurface, &targetDimensions)
由于blitting函数不起作用,我们尝试使用与位图相同的图像(只是将.png导出为.bmp),仍然使用SDL_Image加载文件,这两个函数都按预期使用SDL_BlitScaled缩放
不确定这里出了什么问题(我们希望并需要支持主要的图片文件格式,例如.png),或者如果这是推荐的方法,那么任何帮助都会受到赞赏!
答案 0 :(得分:1)
TL; DR 来自@kelter的评论向我指出了正确的方向,而another stack overflow question给了我一个解决方案:如果你首先Blit到32bpp表面然后BlitScaled到另一个32bpp表面。这适用于8位和24位深度png,32位不可见again another stack overflow question建议首先在blitting之前填充表面。
更新的get_texture函数:
NTE_KEYSET_NOTDEF
来自@kelter的评论让我更仔细地观察表面像素格式,位图工作在24bpp,pngs正在加载8bpp并且无法正常工作。尝试将目标表面更改为24或32 bpp,但这没有帮助。我们已经生成了具有自动检测位深度的png,将其设置为8或24并且在具有相同的每像素位数的表面上执行BlitScaled,尽管它不适用于32.搜索blit转换错误导致来自@Petruza的问答。
更新写这个答案有点快,原始解决方案处理了bmp和8位和24位png但32位png没有渲染。 @Retired Ninja回答另一个关于Blit_Scaled的问题,建议在调用函数之前填充表面并对其进行排序,another question与新表面上的alpha设置有关,可能与此相关(特别是如果你需要透明度)但是填充对我来说,纯色是足够的......现在。