Kaynağa Gözat

Fix filter resolution scale with Masks (#1016)

Pavel Alexandrov 3 yıl önce
ebeveyn
işleme
393b576f3a
5 değiştirilmiş dosya ile 56 ekleme ve 16 silme
  1. 2 0
      h2d/Object.hx
  2. 47 10
      h2d/RenderContext.hx
  3. 4 3
      h2d/filter/AbstractMask.hx
  4. 1 1
      h2d/filter/Ambient.hx
  5. 2 2
      h2d/filter/Mask.hx

+ 2 - 0
h2d/Object.hx

@@ -870,6 +870,8 @@ class Object #if (domkit && !domkit_heaps) implements domkit.Model<h2d.Object> #
 			scaleY = scale.y;
 		}
 
+		ctx.setFilterScale(scaleX, scaleY);
+
 		clipBounds(ctx, total, scaleX, scaleY);
 
 		var xMin = Math.floor(total.xMin + 1e-10);

+ 47 - 10
h2d/RenderContext.hx

@@ -8,6 +8,7 @@ private typedef TargetStackEntry = CameraStackEntry & {
 };
 
 private typedef RenderZoneStack = { hasRZ:Bool, x:Float, y:Float, w:Float, h:Float };
+private typedef FilterStack = { spr: h2d.Object, scaleX:Float, scaleY:Float };
 
 /**
 	A 2D scene renderer.
@@ -96,8 +97,9 @@ class RenderContext extends h3d.impl.RenderContext {
 	var renderZoneStack:Array<RenderZoneStack> = [];
 	var renderZoneIndex:Int = 0;
 	var hasUVPos : Bool;
-	var filterStack : Array<h2d.Object>;
-	var inFilter : Object;
+	var filterStack : Array<FilterStack>;
+	var filterStackIndex : Int;
+	var inFilter : FilterStack;
 	var inFilterBlend : BlendMode;
 
 	var viewA : Float;
@@ -139,6 +141,7 @@ class RenderContext extends h3d.impl.RenderContext {
 		cameraStack = [];
 		cameraStackIndex = 0;
 		filterStack = [];
+		filterStackIndex = 0;
 	}
 
 	override function dispose() {
@@ -297,23 +300,57 @@ class RenderContext extends h3d.impl.RenderContext {
 	public function pushFilter( spr : h2d.Object ) {
 		if( filterStack.length == 0 && onEnterFilter != null )
 			if( !onEnterFilter(spr) ) return false;
-		filterStack.push(spr);
-		inFilter = spr;
+		inFilter = filterStack[filterStackIndex++];
+		if ( inFilter == null ) {
+			inFilter = { spr: null, scaleX: 1, scaleY: 1 };
+			filterStack.push(inFilter);
+		}
+		inFilter.spr = spr;
+		inFilter.scaleX = 1;
+		inFilter.scaleY = 1;
 		return true;
 	}
 
+	/**
+		<span class="label">Internal usage</span>
+
+		Sets the current filter texture resolution scale factor.
+	**/
+	public function setFilterScale( scaleX : Float, scaleY : Float ) {
+		if ( inFilter != null ) {
+			inFilter.scaleX = scaleX;
+			inFilter.scaleY = scaleY;
+		}
+	}
+
+	/**
+		Retrieves the current filter scale factor.
+		
+		@param into The 2D Point instance into which the scale is written. Creates a new Point if null.
+		@returns The current filter resolution scale or `{ 1, 1 }` point.
+	**/
+	public function getFilterScale( ?into : h2d.col.Point ) {
+		if ( into == null ) into = new h2d.col.Point();
+		if ( inFilter != null ) {
+			into.set(inFilter.scaleX, inFilter.scaleY);
+		} else {
+			into.set(1, 1);
+		}
+		return into;
+	}
+
 	/**
 		<span class="label">Internal usage</span>
 
 		Finalizes Filter rendering and removes top-most Object from filter stack.
 	**/
 	public function popFilter() {
-		var spr = filterStack.pop();
-		if( filterStack.length > 0 ) {
-			inFilter = filterStack[filterStack.length - 1];
+		filterStackIndex--;
+		if( filterStackIndex > 0 ) {
+			inFilter = filterStack[filterStackIndex - 1];
 		} else {
 			inFilter = null;
-			if( onLeaveFilter != null ) onLeaveFilter(spr);
+			if( onLeaveFilter != null ) onLeaveFilter(filterStack[filterStackIndex].spr);
 		}
 	}
 
@@ -557,7 +594,7 @@ class RenderContext extends h3d.impl.RenderContext {
 		texture.filter = (currentObj.smooth == null ? defaultSmooth : (currentObj.smooth:Bool)) ? Linear : Nearest;
 		texture.wrap = currentObj.tileWrap && (currentObj.filter == null || inFilter != null) ? Repeat : Clamp;
 		var blend = currentObj.blendMode;
-		if( inFilter == currentObj && blend == Erase ) blend = Add; // add THEN erase
+		if( inFilter != null && inFilter.spr == currentObj && blend == Erase ) blend = Add; // add THEN erase
 		if( inFilterBlend != null ) blend = inFilterBlend;
 		if( blend != currentBlend ) {
 			currentBlend = blend;
@@ -583,7 +620,7 @@ class RenderContext extends h3d.impl.RenderContext {
 	}
 
 	inline function setupColor( obj : h2d.Drawable ) {
-		if( inFilter == obj ) {
+		if( inFilter != null && inFilter.spr == obj ) {
 			baseShader.color.set(obj.color.r,obj.color.g,obj.color.b,obj.color.a);
 		}
 		else if( inFilterBlend != null ) {

+ 4 - 3
h2d/filter/AbstractMask.hx

@@ -96,7 +96,7 @@ class AbstractMask extends Filter {
 		return m;
 	}
 
-	function getMaskTexture( tile : h2d.Tile ) {
+	function getMaskTexture( ctx : h2d.RenderContext, tile : h2d.Tile ) {
 		var t = hide.input == null ? null : hide.input.getTexture();
 		if( t == null ) return null;
 
@@ -110,9 +110,10 @@ class AbstractMask extends Filter {
 		tmpMatrix.prependTranslate(tile.dx, tile.dy);
 		maskMatrix.multiply(tmpMatrix, maskMatrix);
 
+		var resolutionScale = ctx.getFilterScale(@:privateAccess h2d.Object.tmpPoint);
 		// move from tex a to tex b
-		maskMatrix.x /= tile.width;
-		maskMatrix.y /= tile.height;
+		maskMatrix.x /= tile.width / resolutionScale.x;
+		maskMatrix.y /= tile.height / resolutionScale.y;
 
 		maskMatrix.scale(tile.width / hide.inputWidth, tile.height / hide.inputHeight);
 		t.filter = smooth ? Linear : Nearest;

+ 1 - 1
h2d/filter/Ambient.hx

@@ -41,7 +41,7 @@ class Ambient extends AbstractMask {
 
 	override function draw( ctx : RenderContext, t : h2d.Tile ) {
 		var out = ctx.textures.allocTileTarget("ambientTmp", t);
-		pass.apply(t.getTexture(), out, getMaskTexture(t), maskMatrix);
+		pass.apply(t.getTexture(), out, getMaskTexture(ctx, t), maskMatrix);
 		return h2d.Tile.fromTexture(out);
 	}
 

+ 2 - 2
h2d/filter/Mask.hx

@@ -52,7 +52,7 @@ class Mask extends AbstractMask {
 	function set_smoothAlpha(v) return pass.shader.smoothAlpha = v;
 
 	override function draw( ctx : RenderContext, t : h2d.Tile ) {
-		var mask = getMaskTexture(t);
+		var mask = getMaskTexture(ctx, t);
 		if( mask == null ) {
 			if( this.mask == null ) throw "Mask filter has no mask object";
 			return null;
@@ -60,7 +60,7 @@ class Mask extends AbstractMask {
 		var out = ctx.textures.allocTileTarget("maskTmp", t);
 		ctx.engine.pushTarget(out);
 		pass.shader.texture = t.getTexture();
-		pass.shader.mask = getMaskTexture(t);
+		pass.shader.mask = getMaskTexture(ctx, t);
 		pass.shader.maskMatA.set(maskMatrix.a, maskMatrix.c, maskMatrix.x);
 		pass.shader.maskMatB.set(maskMatrix.b, maskMatrix.d, maskMatrix.y);
 		pass.render();