mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-04-21 21:52:04 +02:00
Fix blitting from megatextures
Code mostly taken from the implementation in Bitmap::drawText
This commit is contained in:
parent
8e62dfe68d
commit
bd01e11f56
1 changed files with 148 additions and 112 deletions
|
@ -1058,129 +1058,165 @@ void Bitmap::stretchBlt(IntRect destRect,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SDL_Surface *srcSurf = source.megaSurface();
|
SDL_Surface *srcSurf = source.megaSurface();
|
||||||
|
SDL_Surface *blitTemp = 0;
|
||||||
|
bool touchesTaintedArea = p->touchesTaintedArea(destRect);
|
||||||
|
|
||||||
if (srcSurf && shState->config().subImageFix)
|
if (!srcSurf && opacity == 255 && !touchesTaintedArea)
|
||||||
{
|
|
||||||
/* Blit from software surface, for broken GL drivers */
|
|
||||||
Vec2i gpTexSize;
|
|
||||||
shState->ensureTexSize(sourceRect.w, sourceRect.h, gpTexSize);
|
|
||||||
shState->bindTex();
|
|
||||||
|
|
||||||
GLMeta::subRectImageUpload(srcSurf->w, sourceRect.x, sourceRect.y, 0, 0,
|
|
||||||
sourceRect.w, sourceRect.h, srcSurf, GL_RGBA);
|
|
||||||
GLMeta::subRectImageEnd();
|
|
||||||
|
|
||||||
SimpleShader &shader = shState->shaders().simple;
|
|
||||||
shader.bind();
|
|
||||||
shader.setTranslation(Vec2i());
|
|
||||||
shader.setTexSize(gpTexSize);
|
|
||||||
|
|
||||||
p->pushSetViewport(shader);
|
|
||||||
p->bindFBO();
|
|
||||||
|
|
||||||
Quad &quad = shState->gpQuad();
|
|
||||||
quad.setTexRect(FloatRect(0, 0, sourceRect.w, sourceRect.h));
|
|
||||||
quad.setPosRect(destRect);
|
|
||||||
|
|
||||||
p->blitQuad(quad);
|
|
||||||
p->popViewport();
|
|
||||||
|
|
||||||
p->addTaintedArea(destRect);
|
|
||||||
p->onModified();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (srcSurf)
|
|
||||||
{
|
|
||||||
/* Blit from software surface */
|
|
||||||
/* Don't do transparent blits for now */
|
|
||||||
if (opacity < 255)
|
|
||||||
source.ensureNonMega();
|
|
||||||
|
|
||||||
SDL_Rect srcRect = sourceRect;
|
|
||||||
SDL_Rect dstRect = destRect;
|
|
||||||
SDL_Rect btmRect = { 0, 0, width(), height() };
|
|
||||||
SDL_Rect bltRect;
|
|
||||||
|
|
||||||
if (SDL_IntersectRect(&btmRect, &dstRect, &bltRect) != SDL_TRUE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int bpp;
|
|
||||||
Uint32 rMask, gMask, bMask, aMask;
|
|
||||||
SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888,
|
|
||||||
&bpp, &rMask, &gMask, &bMask, &aMask);
|
|
||||||
SDL_Surface *blitTemp =
|
|
||||||
SDL_CreateRGBSurface(0, destRect.w, destRect.h, bpp, rMask, gMask, bMask, aMask);
|
|
||||||
|
|
||||||
SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0);
|
|
||||||
|
|
||||||
TEX::bind(getGLTypes().tex);
|
|
||||||
|
|
||||||
if (bltRect.w == dstRect.w && bltRect.h == dstRect.h)
|
|
||||||
{
|
|
||||||
/* Dest rectangle lies within bounding box */
|
|
||||||
TEX::uploadSubImage(destRect.x, destRect.y,
|
|
||||||
destRect.w, destRect.h,
|
|
||||||
blitTemp->pixels, GL_RGBA);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Clipped blit */
|
|
||||||
GLMeta::subRectImageUpload(blitTemp->w, bltRect.x - dstRect.x, bltRect.y - dstRect.y,
|
|
||||||
bltRect.x, bltRect.y, bltRect.w, bltRect.h, blitTemp, GL_RGBA);
|
|
||||||
GLMeta::subRectImageEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_FreeSurface(blitTemp);
|
|
||||||
|
|
||||||
p->onModified();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opacity == 255 && !p->touchesTaintedArea(destRect))
|
|
||||||
{
|
{
|
||||||
/* Fast blit */
|
/* Fast blit */
|
||||||
GLMeta::blitBegin(getGLTypes());
|
GLMeta::blitBegin(getGLTypes());
|
||||||
GLMeta::blitSource(source.getGLTypes());
|
GLMeta::blitSource(source.getGLTypes());
|
||||||
GLMeta::blitRectangle(sourceRect, destRect);
|
GLMeta::blitRectangle(sourceRect, destRect, false);
|
||||||
GLMeta::blitEnd();
|
GLMeta::blitEnd();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Fragment pipeline */
|
if (srcSurf)
|
||||||
float normOpacity = (float) opacity / 255.0f;
|
{
|
||||||
|
SDL_Rect srcRect = sourceRect;
|
||||||
TEXFBO &gpTex = shState->gpTexFBO(destRect.w, destRect.h);
|
bool subImageFix = shState->config().subImageFix;
|
||||||
|
bool srcRectTooBig = srcRect.w > glState.caps.maxTexSize ||
|
||||||
GLMeta::blitBegin(gpTex);
|
srcRect.h > glState.caps.maxTexSize;
|
||||||
GLMeta::blitSource(getGLTypes());
|
bool srcSurfTooBig = srcSurf->w > glState.caps.maxTexSize ||
|
||||||
GLMeta::blitRectangle(destRect, Vec2i());
|
srcSurf->h > glState.caps.maxTexSize;
|
||||||
GLMeta::blitEnd();
|
|
||||||
|
if (srcRectTooBig || srcSurfTooBig)
|
||||||
FloatRect bltSubRect((float) sourceRect.x / source.width(),
|
{
|
||||||
(float) sourceRect.y / source.height(),
|
int error;
|
||||||
((float) source.width() / sourceRect.w) * ((float) destRect.w / gpTex.width),
|
if (srcRectTooBig)
|
||||||
((float) source.height() / sourceRect.h) * ((float) destRect.h / gpTex.height));
|
{
|
||||||
|
/* We have to resize it here anyway, so use software resizing */
|
||||||
BltShader &shader = shState->shaders().blt;
|
blitTemp =
|
||||||
shader.bind();
|
SDL_CreateRGBSurface(0, abs(destRect.w), abs(destRect.h), p->format->BitsPerPixel,
|
||||||
shader.setDestination(gpTex.tex);
|
p->format->Rmask, p->format->Gmask,
|
||||||
shader.setSubRect(bltSubRect);
|
p->format->Bmask, p->format->Amask);
|
||||||
shader.setOpacity(normOpacity);
|
if (!blitTemp)
|
||||||
|
throw Exception(Exception::SDLError, "Error creating temporary surface for blitting: %s",
|
||||||
Quad &quad = shState->gpQuad();
|
SDL_GetError());
|
||||||
quad.setTexPosRect(sourceRect, destRect);
|
|
||||||
quad.setColor(Vec4(1, 1, 1, normOpacity));
|
error = SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0);
|
||||||
|
}
|
||||||
source.p->bindTexture(shader, false);
|
else
|
||||||
p->bindFBO();
|
{
|
||||||
p->pushSetViewport(shader);
|
/* Just crop it, let the shader resize it later */
|
||||||
|
blitTemp =
|
||||||
p->blitQuad(quad);
|
SDL_CreateRGBSurface(0, sourceRect.w, sourceRect.h, p->format->BitsPerPixel,
|
||||||
|
p->format->Rmask, p->format->Gmask,
|
||||||
p->popViewport();
|
p->format->Bmask, p->format->Amask);
|
||||||
|
if (!blitTemp)
|
||||||
|
throw Exception(Exception::SDLError, "Error creating temporary surface for blitting: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
|
||||||
|
error = SDL_BlitSurface(srcSurf, &srcRect, blitTemp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(blitTemp);
|
||||||
|
throw Exception(Exception::SDLError, "Failed to blit surface: %s", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
srcSurf = blitTemp;
|
||||||
|
|
||||||
|
sourceRect.w = srcSurf->w;
|
||||||
|
sourceRect.h = srcSurf->h;
|
||||||
|
sourceRect.x = 0;
|
||||||
|
sourceRect.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opacity == 255 && !touchesTaintedArea)
|
||||||
|
{
|
||||||
|
if (!subImageFix &&
|
||||||
|
sourceRect.w == destRect.w && sourceRect.h == destRect.h &&
|
||||||
|
srcSurf->w == sourceRect.w && srcSurf->h == sourceRect.h)
|
||||||
|
{
|
||||||
|
/* No scaling needed */
|
||||||
|
TEX::bind(getGLTypes().tex);
|
||||||
|
TEX::uploadSubImage(destRect.x, destRect.y,
|
||||||
|
destRect.w, destRect.h,
|
||||||
|
srcSurf->pixels, GL_RGBA);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Resizing or subImageFix involved: need to use intermediary TexFBO */
|
||||||
|
TEXFBO &gpTF = shState->gpTexFBO(srcSurf->w, srcSurf->h);
|
||||||
|
|
||||||
|
TEX::bind(gpTF.tex);
|
||||||
|
TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA);
|
||||||
|
|
||||||
|
GLMeta::blitBegin(getGLTypes());
|
||||||
|
GLMeta::blitSource(gpTF);
|
||||||
|
GLMeta::blitRectangle(sourceRect, destRect, false);
|
||||||
|
GLMeta::blitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opacity < 255 || touchesTaintedArea)
|
||||||
|
{
|
||||||
|
/* We're touching a tainted area or still need to reduce opacity */
|
||||||
|
|
||||||
|
/* Fragment pipeline */
|
||||||
|
float normOpacity = (float) opacity / 255.0f;
|
||||||
|
|
||||||
|
TEXFBO &gpTex = shState->gpTexFBO(abs(destRect.w), abs(destRect.h));
|
||||||
|
Vec2i gpTexSize;
|
||||||
|
|
||||||
|
GLMeta::blitBegin(gpTex);
|
||||||
|
GLMeta::blitSource(getGLTypes());
|
||||||
|
GLMeta::blitRectangle(destRect, IntRect(0, 0, abs(destRect.w), abs(destRect.h)));
|
||||||
|
GLMeta::blitEnd();
|
||||||
|
|
||||||
|
int sourceWidth, sourceHeight;
|
||||||
|
FloatRect bltSubRect;
|
||||||
|
if (srcSurf)
|
||||||
|
{
|
||||||
|
shState->ensureTexSize(srcSurf->w, srcSurf->h, gpTexSize);
|
||||||
|
sourceWidth = gpTexSize.x;
|
||||||
|
sourceHeight = gpTexSize.y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sourceWidth = source.width();
|
||||||
|
sourceHeight = source.height();
|
||||||
|
}
|
||||||
|
bltSubRect = FloatRect((float) sourceRect.x / sourceWidth,
|
||||||
|
(float) sourceRect.y / sourceHeight,
|
||||||
|
((float) sourceWidth / sourceRect.w) * ((float) abs(destRect.w) / gpTex.width),
|
||||||
|
((float) sourceHeight / sourceRect.h) * ((float) abs(destRect.h) / gpTex.height));
|
||||||
|
|
||||||
|
BltShader &shader = shState->shaders().blt;
|
||||||
|
shader.bind();
|
||||||
|
if (srcSurf)
|
||||||
|
{
|
||||||
|
shState->bindTex();
|
||||||
|
TEX::uploadSubImage(0, 0, srcSurf->w, srcSurf->h, srcSurf->pixels, GL_RGBA);
|
||||||
|
shader.setTexSize(gpTexSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.p->bindTexture(shader, false);
|
||||||
|
}
|
||||||
|
shader.setSource();
|
||||||
|
shader.setDestination(gpTex.tex);
|
||||||
|
shader.setSubRect(bltSubRect);
|
||||||
|
shader.setOpacity(normOpacity);
|
||||||
|
|
||||||
|
Quad &quad = shState->gpQuad();
|
||||||
|
quad.setTexPosRect(sourceRect, destRect);
|
||||||
|
quad.setColor(Vec4(1, 1, 1, normOpacity));
|
||||||
|
|
||||||
|
p->bindFBO();
|
||||||
|
p->pushSetViewport(shader);
|
||||||
|
|
||||||
|
p->blitQuad(quad);
|
||||||
|
|
||||||
|
p->popViewport();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blitTemp)
|
||||||
|
SDL_FreeSurface(blitTemp);
|
||||||
|
|
||||||
p->addTaintedArea(destRect);
|
p->addTaintedArea(destRect);
|
||||||
p->onModified();
|
p->onModified();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue