Ejemplo n.º 1
0
void Bitmap::stretchBlt(const IntRect &destRect,
                        const Bitmap &source, const IntRect &sourceRect,
                        int opacity)
{
	GUARD_DISPOSED;

	GUARD_MEGA;

	opacity = clamp(opacity, 0, 255);

	if (opacity == 0)
		return;

	if (source.megaSurface())
	{
		/* Don't do transparent blits for now */
		if (opacity < 255)
			source.ensureNonMega();

		SDL_Surface *srcSurf = source.megaSurface();

		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_Rect srcRect;
		srcRect.x = sourceRect.x;
		srcRect.y = sourceRect.y;
		srcRect.w = sourceRect.w;
		srcRect.h = sourceRect.h;

		SDL_Rect dstRect;
		dstRect.x = dstRect.y = 0;
		dstRect.w = blitTemp->w;
		dstRect.h = blitTemp->h;

		// FXIME: This is supposed to be a scaled blit, put SDL2 for some reason
		// makes the source surface unusable after BlitScaled() is called. Investigate!
		SDL_BlitSurface(srcSurf, &srcRect, blitTemp, &dstRect);

		TEX::bind(p->gl.tex);
		TEX::uploadSubImage(destRect.x, destRect.y, destRect.w, destRect.h, blitTemp->pixels, GL_RGBA);

		SDL_FreeSurface(blitTemp);

		modified();
		return;
	}

	if (opacity == 255 && !p->touchesTaintedArea(destRect))
	{
		/* Fast blit */
		FBO::bind(source.p->gl.fbo, FBO::Read);
		FBO::bind(p->gl.fbo, FBO::Draw);

		FBO::blit(sourceRect.x, sourceRect.y, sourceRect.w, sourceRect.h,
		          destRect.x,   destRect.y,   destRect.w,   destRect.h);
	}
	else
	{
		/* Fragment pipeline */
		float normOpacity = (float) opacity / 255.0f;

		TEXFBO &gpTex = shState->gpTexFBO(destRect.w, destRect.h);

		FBO::bind(gpTex.fbo, FBO::Draw);
		FBO::bind(p->gl.fbo, FBO::Read);
		FBO::blit(destRect.x, destRect.y, 0, 0, destRect.w, destRect.h);

		FloatRect bltSubRect((float) sourceRect.x / source.width(),
		                     (float) sourceRect.y / source.height(),
		                     ((float) source.width() / sourceRect.w) * ((float) destRect.w / gpTex.width),
		                     ((float) source.height() / sourceRect.h) * ((float) destRect.h / gpTex.height));

		BltShader &shader = shState->shaders().blt;
		shader.bind();
		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));

		source.p->bindTexture(shader);
		p->bindFBO();
		p->pushSetViewport(shader);

		p->blitQuad(quad);

		p->popViewport();
	}

	p->addTaintedArea(destRect);

	modified();
}
Ejemplo n.º 2
0
void Bitmap::stretchBlt(const IntRect &destRect,
                        const Bitmap &source, const IntRect &sourceRect,
                        int opacity)
{
	guardDisposed();

	GUARD_MEGA;

	if (source.isDisposed())
		return;

	opacity = clamp(opacity, 0, 255);

	if (opacity == 0)
		return;

	SDL_Surface *srcSurf = source.megaSurface();

	if (srcSurf && shState->config().subImageFix)
	{
		/* 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(p->gl.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 */
		GLMeta::blitBegin(p->gl);
		GLMeta::blitSource(source.p->gl);
		GLMeta::blitRectangle(sourceRect, destRect);
		GLMeta::blitEnd();
	}
	else
	{
		/* Fragment pipeline */
		float normOpacity = (float) opacity / 255.0f;

		TEXFBO &gpTex = shState->gpTexFBO(destRect.w, destRect.h);

		GLMeta::blitBegin(gpTex);
		GLMeta::blitSource(p->gl);
		GLMeta::blitRectangle(destRect, Vec2i());
		GLMeta::blitEnd();

		FloatRect bltSubRect((float) sourceRect.x / source.width(),
		                     (float) sourceRect.y / source.height(),
		                     ((float) source.width() / sourceRect.w) * ((float) destRect.w / gpTex.width),
		                     ((float) source.height() / sourceRect.h) * ((float) destRect.h / gpTex.height));

		BltShader &shader = shState->shaders().blt;
		shader.bind();
		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));

		source.p->bindTexture(shader);
		p->bindFBO();
		p->pushSetViewport(shader);

		p->blitQuad(quad);

		p->popViewport();
	}

	p->addTaintedArea(destRect);
	p->onModified();
}