Tilemap render issue

I use bitmaps to draw through the drawTriangles in the Sprite, then add the tilemap object. When tile.scaleX=-1 is set, the tile will not be visible.

The following is a pseudo code:

var draw = new Sprite();
draw.graphics.clear();
draw.graphics.beginBitmapFill(textureAtlas.getRootBitmapData(), null, true, true);
draw.graphics.drawTriangles(vertices, indices, uv);
draw.graphics.endFill();
this.addChild(draw);

var tilemap = new Tilemap();
this.addChild(tilemap);
...tile.scaleX = -1; //visible error!

This happened in openfl8.9.2, which was a troublesome issue for me.

This can happen in any browser.

@singmajesty

What if you use tile.scaleX = -1 and tile.x = 100 (or some other positive value)?

I think the tile is being flipped but also being cropped outside the edges of the Tilemap

Sorry, this is not mentioned in the example. Even if you modify x = 100, the display object will not be displayed.

After testing, this still happens in OpenFL8.9.4.

I just tried scaleX = -1 on the BunnyMark demo and I still got Tilemap rendering

Could this be a different issue you are seeing?

package;


import lime.ui.Gamepad;
import lime.ui.GamepadButton;
import openfl.display.FPS;
import openfl.display.Sprite;
import openfl.display.Tile;
import openfl.display.Tilemap;
import openfl.display.Tileset;
import openfl.events.Event;
import openfl.events.MouseEvent;
import openfl.utils.Assets;
import openfl.Vector;


class Main extends Sprite {
	
	
	private var addingBunnies:Bool;
	private var bunnies:Array<Bunny>;
	private var fps:FPS;
	private var gravity:Float;
	private var minX:Int;
	private var minY:Int;
	private var maxX:Int;
	private var maxY:Int;
	private var tileset:Tileset;
	
	#if (flash || use_tilemap)
	private var tilemap:Tilemap;
	#else
	private var indices:Vector<Int>;
	private var transforms:Vector<Float>;
	#end
	
	
	public function new () {
		
		super ();
		
		bunnies = new Array ();
		
		minX = 0;
		maxX = stage.stageWidth;
		minY = 0;
		maxY = stage.stageHeight;
		gravity = 0.5;
		
		var bitmapData = Assets.getBitmapData ("assets/wabbit_alpha.png");
		tileset = new Tileset (bitmapData);
		tileset.addRect (bitmapData.rect);

		var spr:Sprite = new Sprite();
		this.addChild(spr);
		spr.graphics.beginBitmapFill(bitmapData);
		var v1:Array<Float> = [0,0,100,0,100,200,0,200];
		var v2:Array<Int> = [0,1,2,2,3,4];
		var v3:Array<Float> = [0,0,0,1,0,1,1,1];
		spr.graphics.drawTriangles(ofArray(v1),ofArray(v2),ofArray(v3));
		spr.graphics.endFill();
		spr.x = 200;
		spr.y = 200;
		
		#if (flash || use_tilemap)
		tilemap = new Tilemap (stage.stageWidth, stage.stageHeight, tileset);
		tilemap.tileAlphaEnabled = false;
		tilemap.tileBlendModeEnabled = false;
		tilemap.tileColorTransformEnabled = false;
		addChild (tilemap);
		#else
		indices = new Vector<Int> ();
		transforms = new Vector<Float> ();
		#end
		
		#if !html5
		fps = new FPS ();
		#if !hide_fps
		addChild (fps);
		#end
		#end
		
		stage.addEventListener (MouseEvent.MOUSE_DOWN, stage_onMouseDown);
		stage.addEventListener (MouseEvent.MOUSE_UP, stage_onMouseUp);
		stage.addEventListener (Event.ENTER_FRAME, stage_onEnterFrame);
		stage.addEventListener (Event.RESIZE, stage_onResize);
		
		Gamepad.onConnect.add (gamepad_onConnect);
		
		for (gamepad in Gamepad.devices) {
			gamepad_onConnect (gamepad);
		}
		
		var count = #if bunnies Std.parseInt (haxe.macro.Compiler.getDefine ("bunnies")) #else 100 #end;
		
		for (i in 0...count) {
			
			addBunny ();
			
		}
		
	}
	
	@:generic public inline static function ofArray<T>(array:Array<T>):Vector<T>
	{
		var vector:Vector<T> = new Vector<T>();

		for (i in 0...array.length)
		{
			vector[i] = cast array[i];
		}

		return vector;
	}
	
	private function addBunny ():Void {
		
		var bunny = new Bunny ();
		bunny.x = 0;
		bunny.y = 0;
		bunny.speedX = Math.random () * 5;
		bunny.speedY = (Math.random () * 5) - 2.5;
		bunnies.push (bunny);
		
		#if (!flash && !use_tilemap)
		indices.push (bunny.id);
		transforms.push (0);
		transforms.push (0);
		#else
		if(Math.random() > 0.5)
			bunny.scaleX = -2;
		tilemap.addTile (bunny);
		#end
		
	}
	
	
	
	
	// Event Handlers
	
	
	
	
	private function gamepad_onButtonDown (button:GamepadButton):Void {
		
		addingBunnies = true;
		
	}
	
	
	private function gamepad_onButtonUp (button:GamepadButton):Void {
		
		addingBunnies = false;
		trace (bunnies.length + " bunnies");
		
	}
	
	
	private function gamepad_onConnect (gamepad:Gamepad):Void {
		
		gamepad.onButtonDown.add (gamepad_onButtonDown);
		gamepad.onButtonUp.add (gamepad_onButtonUp);
		
	}
	
	
	private function stage_onEnterFrame (event:Event):Void {
		
		var bunny;
		
		for (i in 0...bunnies.length) {
			
			bunny = bunnies[i];
			
			bunny.x += bunny.speedX;
			bunny.y += bunny.speedY;
			bunny.speedY += gravity;
			
			if (bunny.x > maxX) {
				
				bunny.speedX *= -1;
				bunny.x = maxX;
				
			} else if (bunny.x < minX) {
				
				bunny.speedX *= -1;
				bunny.x = minX;
				
			}
			
			if (bunny.y > maxY) {
				
				bunny.speedY *= -0.8;
				bunny.y = maxY;
				
				if (Math.random () > 0.5) {
					
					bunny.speedY -= 3 + Math.random () * 4;
					
				}
				
			} else if (bunny.y < minY) {
				
				bunny.speedY = 0;
				bunny.y = minY;
				
			}
			
			#if (!flash && !use_tilemap)
			transforms[i * 2] = bunny.x;
			transforms[i * 2 + 1] = bunny.y;
			#end
			
		}
		
		#if (!flash && !use_tilemap)
		graphics.clear ();
		graphics.beginFill (0xFFFFFF);
		graphics.drawRect (0, 0, stage.stageWidth, stage.stageHeight);
		graphics.beginBitmapFill (tileset.bitmapData, null, false);
		graphics.drawQuads (tileset.rectData, indices, transforms);
		#end
		
		if (addingBunnies) {
			
			#if hide_fps
			trace (fps.currentFPS);
			#end
			
			for (i in 0...100) {
				
				addBunny ();
				
			}
			
		}
		
	}
	
	
	private function stage_onMouseDown (event:MouseEvent):Void {
		
		addingBunnies = true;
		
	}
	
	
	private function stage_onMouseUp (event:MouseEvent):Void {
		
		addingBunnies = false;
		trace (bunnies.length + " bunnies");
		
	}
	
	
	private function stage_onResize (event:Event):Void {
		
		maxX = stage.stageWidth;
		maxY = stage.stageHeight;
		
		#if (flash || use_tilemap)
		tilemap.width = stage.stageWidth;
		tilemap.height = stage.stageHeight;
		#end
		
	}
	
	
}

You need to use spr.graphics.beginBitmapFill and spr.graphics.drawTriangles.

I provided a case where I used the <haxedef name="use_tilemap"/> tag and added a Sprite object with the following test code:

if(Math.random() > 0.5)
       bunny.scaleX = -2;
tilemap.addTile (bunny);

You won’t see the tile display object with scale = -2.

Tips:This case will have a non-power-of-2 error.

Flash and native seem different when omitting the uvtData value but when it is included I am able to see the same thing on both

var spr:Sprite = new Sprite();
this.addChild(spr);
spr.graphics.beginBitmapFill(bitmapData);
var v1:Array<Float> = [0,0,bitmapData.width,0,bitmapData.width,bitmapData.height,0,bitmapData.height];
var v2:Array<Int> = [0,1,2,2,3,0];
var v3:Array<Float> = [0,0,1,0,1,1,0,1];
spr.graphics.drawTriangles(ofArray(v1),ofArray(v2),ofArray(v3));
spr.graphics.endFill();
spr.x = 200;
spr.y = 200;

…also adding this code it appears to look the same:

var bitmapData2 = new BitmapData(bitmapData.width, bitmapData.height, true, 0);
bitmapData2.draw(spr);

tileset.bitmapData = bitmapData2;

It is worth mentioning however that bitmapData.draw forces a software render which uses a software version of drawTriangles rather than hardware which may have different results

It seems that there is a problem with the rendering of the Context3DTilemap class. I can use <define name="canvas"/> to render properly. but I need webgl.

Hi, I came back to this problem again. Sprite needs to be below the tilemap layer to affect the tile display. Even I encountered the same problem in Openfl9.0.2.

Use beginFill Api:

Use beginBitmapFill Api:

Code:

                        _shape.graphics.beginFill(0xff0000);
			// _shape.graphics.beginBitmapFill(bitmapData, null, false, false);
			_shape.graphics.drawTriangles(allVerticesArray, allTriangles, null, TriangleCulling.NONE);
			_shape.graphics.endFill();

Can you help me thanks!

In the example below, the black block has disappeared!

beginBitmapFill + drawTriangles Will affect the display object of scaleX=-1, has no one encountered this problem?

_shape.graphics.clear();
			_shape.graphics.beginBitmapFill(bitmapData, null, false, false);
			_shape.graphics.drawTriangles(allVerticesArray, allTriangles, allUvs, TriangleCulling.NONE);
			_shape.graphics.beginFill(0xff0000);
			_shape.graphics.drawTriangles(ofArrayFloat([0,0,0,10,10,0]),ofArrayInt([0,1,2]));
			_shape.graphics.endFill();

The above example can display the square normally, but it will affect the triangle with scaleX=-1 on the right…

I found the location of the problem:

context.setCulling(BACK);

I improved the API of endFill:

context.setCulling(NONE);

Fix: https://github.com/openfl/openfl/pull/2417