[HTML5] stage.fullScreenSourceRect

Hi all,

I’m trying to switch a section of my app to fullscreen.
On Flash target, we can use stage.fullScreenSourceRect.
But this is not available/implemented on HTML5 target :frowning:
So I’m trying to find a way to achieve the same result.

Here is the issue I have created on GitHub :

Any ideas / suggestions ?

Thank you in advance!

I would look here:

The __displayMatrix should affect how the Stage renders. It works (at least) on OpenGL, and could be respected elsewhere. Further support for stage.displayMode as well as fullScreenSourceRect would ultimately change what __displayMatrix value we use.

Please share if you make any progress or have questions :slight_smile:

Thank you for pointing out the relevant code.
So, I’m able to alter the rendering by changing stageWidth & stageHeight.
However, when switching to fullscreen, it doesn’t affect the container (e.g. window) so the stage is rendered in a small portion, instead of taking all space.
I have tried to use stage.window.resize() instead, but for some reason it makes the stage rendered at a wrong offset and the container still has the original dimensions so I get empty space all around the stage :frowning:

Here is a sample code to reproduce the problem :

import openfl.Lib;
import openfl.display.Sprite;
import openfl.display.StageDisplayState;
import openfl.events.MouseEvent;

static function main()
{
	var s:Sprite = new Sprite();
	s.graphics.beginFill( 0xFF0000 );
	s.graphics.drawRect( 0, 0, 200, 200 );
	s.graphics.endFill();
	s.graphics.beginFill( 0x0000FF );
	s.graphics.drawRect( 50, 50, 100, 100 );
	s.graphics.endFill();
	s.addEventListener( MouseEvent.MOUSE_DOWN, function( e:MouseEvent )
		{
			Lib.current.stage.window.resize( 100, 100 );
			Lib.current.stage.displayState = StageDisplayState.FULL_SCREEN;
		}
	);
	Lib.current.stage.addChild( s );
}

It should display a 200x200 red square, with a 100x100 blue square inside.
When clicking on it, it will switch to fullscreen, but the whole sprite is currently visible (instead of displaying only a part of it).
Changing web browser tab back & forth does refresh the stage and then shows the left/top section of the sprite (which is correct), but at the wrong position.

Try and change the displayMatrix, instead of the stage width and height. For example, you could scale up the matrix by 2, to keep the same screen resolution, but display all the stage content at double the size. We might not be able to change the display resolution to match the desired rectangle, but we should be able to scale the content so that that is all that’s visible

Changing scale works, but it doesn’t extend the screen so I can’t get the same result as on Flash target.

Here is an updated code sample :

import flash.Lib;
import flash.display.Sprite;
import flash.display.StageDisplayState;
import flash.events.MouseEvent;
import flash.geom.Rectangle;

static function main()
{
	var s:Sprite = new Sprite();
	s.graphics.beginFill( 0xFF0000 );
	s.graphics.drawRect( 0, 0, 800, 600 );
	s.graphics.endFill();
	s.graphics.beginFill( 0x0000FF );
	s.graphics.drawRect( 50, 50, 700, 300 );
	s.graphics.endFill();
	s.addEventListener( MouseEvent.MOUSE_DOWN, function( e:MouseEvent )
		{
			#if flash
			Lib.current.stage.fullScreenSourceRect = new Rectangle( 0, 0, 800, 400 );
			#end
			Lib.current.stage.displayState = StageDisplayState.FULL_SCREEN;
		}
	);
	Lib.current.stage.addChild( s );
}

For quick testing on HTML5, I patched Stage.hx :

			...
			stageWidth = __logicalWidth;
			stageHeight = __logicalHeight;
			
			if ( window.fullscreen )
			{
				// TEST
				stageHeight = 400;
			}
			
			var scaleX = windowWidth / stageWidth;
			var scaleY = windowHeight / stageHeight;
			var targetScale = Math.min (scaleX, scaleY);
			...

Project settings :
<window width="800" height="600" />
<window background="#ffffff" fps="60" />

Here are screenshots of what I get when clicking on the sprite to switch to fullscreen :
FLASH : https://i.imgur.com/jGDKUVJ.png
HTML5 : https://i.imgur.com/yTqb8pe.png

As you can see, Flash uses the whole screen, as expected.
But on HTML5, the viewport seems to be stuck to its original dimensions.

Have you tried leaving stageWidth and stageHeight alone, and changing the displayMatrix instead?

Does changing fullScreenSourceRect alter the stageWidth/stageHeight reported values?

Yes, I tried to force a scale on __displayMatrix : it makes the stage zoomed (as expected) but it stays inside its “container”, so the content is cropped.
Using fullScreenSourceRect on Flash doesn’t seem to affect stageWidth/stageHeight properties.
As you mentionned, I think we need something to change the logical “resolution” to make it work like Flash.

By clipping, do you mean the black letterboxing? I believe this is applied by the __displayMatrix.tx or __displayMatrix.ty property

The black letterboxing is indeed due to the offsetY=100 applied to __displayMatrix in this case.
In fact, whatever I change in __displayMatrix, it will still stay inside the “container”, so the left/right white borders are always there.
Maybe we should patch the canvas element dimensions to let the browser do the job, since the default rule is width=100%; height=100% ?

I made more tests, and figured out I could achieve the result I wanted by changing the height from 600 to 400 in the generated index.html :
lime.embed ("MyApp, "openfl-content", 800, 400, { parameters: {} });

Now the question is : how can I change the window size properties during runtime ?
I have tried openfl.Lib.current.stage.window.resize(), but it didn’t work.

Any suggestions ?

I managed to get it work by patching a few internal properties (for tests) :

import flash.Lib;
import flash.display.Sprite;
import flash.display.StageDisplayState;
import flash.events.MouseEvent;
import flash.geom.Rectangle;

var stage:flash.display.Stage = Lib.current.stage;
var s:Sprite = new Sprite();
s.graphics.beginFill( 0xFF0000 );
s.graphics.drawRect( 0, 0, 800, 600 );
s.graphics.endFill();
s.graphics.beginFill( 0x0000FF );
s.graphics.drawRect( 50, 50, 700, 300 );
s.graphics.endFill();

s.addEventListener( MouseEvent.MOUSE_DOWN, function( e:MouseEvent )
	{
		var fs:Bool = ( stage.displayState==StageDisplayState.NORMAL );
		#if flash
			stage.fullScreenSourceRect = new Rectangle( 0, 0, 800, 400 );
		#else
			var w:lime.ui.Window = stage.window;
			var h:Int = fs ? 400 : 600;
			w.height = h;
			stage.onWindowResize( w, w.width, w.height );
			var c:js.html.CanvasElement = @:privateAccess w.backend.canvas;
			c.height = h;
			var bw:lime._backend.html5.HTML5Window = @:privateAccess w.backend;
			@:privateAccess bw.setHeight = h;
			@:privateAccess bw.updateSize();
		#end
		stage.displayState = fs ? StageDisplayState.FULL_SCREEN : StageDisplayState.NORMAL;
	}
);
stage.addChild( s );

However, implementing a clean version (with fullScreenSourceRect) seem quite complex for me :frowning:
Any help is welcome!

Moreover, exiting fullscreen with ESC key doesn’t restore the window in its original state (unlike Flash), but I will open another issue for this.