浏览代码

Implement 2D Scene ScaleMode (#595)

Pavel Alexandrov 6 年之前
父节点
当前提交
74b792c363
共有 3 个文件被更改,包括 355 次插入41 次删除
  1. 29 10
      h2d/RenderContext.hx
  2. 249 31
      h2d/Scene.hx
  3. 77 0
      samples/ScaleMode2D.hx

+ 29 - 10
h2d/RenderContext.hx

@@ -93,7 +93,7 @@ class RenderContext extends h3d.impl.RenderContext {
 		// todo : we might prefer to auto-detect this by running a test and capturing its output
 		// todo : we might prefer to auto-detect this by running a test and capturing its output
 		baseShader.pixelAlign = #if flash true #else false #end;
 		baseShader.pixelAlign = #if flash true #else false #end;
 		baseShader.halfPixelInverse.set(0.5 / engine.width, 0.5 / engine.height);
 		baseShader.halfPixelInverse.set(0.5 / engine.width, 0.5 / engine.height);
-		baseShader.viewport.set( -scene.width * 0.5, -scene.height * 0.5, 2 / scene.width, -2 * baseFlipY / scene.height);
+		baseShader.viewport.set( -scene.width * 0.5 - scene.offsetX, -scene.height * 0.5 - scene.offsetY, 2 / scene.width * scene.ratioX, -2 * baseFlipY / scene.height * scene.ratioY);
 		baseShader.filterMatrixA.set(1, 0, 0);
 		baseShader.filterMatrixA.set(1, 0, 0);
 		baseShader.filterMatrixB.set(0, 1, 0);
 		baseShader.filterMatrixB.set(0, 1, 0);
 		baseShaderList.next = null;
 		baseShaderList.next = null;
@@ -190,14 +190,33 @@ class RenderContext extends h3d.impl.RenderContext {
 
 
 		if( restore ) {
 		if( restore ) {
 			var tinf = targetsStack[targetsStackIndex - 1];
 			var tinf = targetsStack[targetsStackIndex - 1];
-			var t = tinf == null ? null : tinf.t;
-			var startX = tinf == null ? 0 : tinf.x;
-			var startY = tinf == null ? 0 : tinf.y;
-			var width = tinf == null ? scene.width : tinf.w;
-			var height = tinf == null ? scene.height : tinf.h;
+			var t : h3d.mat.Texture;
+			var startX : Int, startY : Int, width : Int, height : Int;
+			var ratioX : Float, ratioY : Float, offsetX : Float, offsetY : Float;
+			if ( tinf == null ) {
+				t = null;
+				startX = 0;
+				startY = 0;
+				width = scene.width;
+				height = scene.height;
+				ratioX = scene.ratioX;
+				ratioY = scene.ratioY;
+				offsetX = scene.offsetX;
+				offsetY = scene.offsetY;
+			} else {
+				t = tinf.t;
+				startX = tinf.x;
+				startY = tinf.y;
+				width = tinf.w;
+				height = tinf.h;
+				ratioX = 1;
+				ratioY = 1;
+				offsetX = 0;
+				offsetY = 0;
+			}
 			initShaders(baseShaderList);
 			initShaders(baseShaderList);
 			baseShader.halfPixelInverse.set(0.5 / (t == null ? engine.width : t.width), 0.5 / (t == null ? engine.height : t.height));
 			baseShader.halfPixelInverse.set(0.5 / (t == null ? engine.width : t.width), 0.5 / (t == null ? engine.height : t.height));
-			baseShader.viewport.set( -width * 0.5 - startX, -height * 0.5 - startY, 2 / width, -2 * (t == null ? baseFlipY : targetFlipY) / height);
+			baseShader.viewport.set( -width * 0.5 - startX - offsetX, -height * 0.5 - startY - offsetY, 2 / width * ratioX, -2 * (t == null ? baseFlipY : targetFlipY) / height * ratioY);
 			curX = startX;
 			curX = startX;
 			curY = startY;
 			curY = startY;
 			curWidth = width;
 			curWidth = width;
@@ -213,8 +232,8 @@ class RenderContext extends h3d.impl.RenderContext {
 		renderY = y;
 		renderY = y;
 		renderW = w;
 		renderW = w;
 		renderH = h;
 		renderH = h;
-		var scaleX = engine.width / scene.width;
-		var scaleY = engine.height / scene.height;
+		var scaleX = engine.width * scene.ratioX / scene.width;
+		var scaleY = engine.height * scene.ratioY / scene.height;
 		if( inFilter != null ) {
 		if( inFilter != null ) {
 			var fa = baseShader.filterMatrixA;
 			var fa = baseShader.filterMatrixA;
 			var fb = baseShader.filterMatrixB;
 			var fb = baseShader.filterMatrixB;
@@ -228,7 +247,7 @@ class RenderContext extends h3d.impl.RenderContext {
 			w = rx2 - rx1;
 			w = rx2 - rx1;
 			h = ry2 - ry1;
 			h = ry2 - ry1;
 		}
 		}
-		engine.setRenderZone(Std.int((x - curX) * scaleX + 1e-10), Std.int((y - curY) * scaleY + 1e-10), Std.int(w * scaleX + 1e-10), Std.int(h * scaleY + 1e-10));
+		engine.setRenderZone(Std.int((x - curX + scene.viewportX) * scaleX + 1e-10), Std.int((y - curY + scene.viewportY) * scaleY + 1e-10), Std.int(w * scaleX + 1e-10), Std.int(h * scaleY + 1e-10));
 	}
 	}
 
 
 	public inline function clearRenderZone() {
 	public inline function clearRenderZone() {

+ 249 - 31
h2d/Scene.hx

@@ -1,21 +1,117 @@
 package h2d;
 package h2d;
 import hxd.Math;
 import hxd.Math;
 
 
+/**
+	Viewport alignment when scaling mode supports it.
+**/
+enum ScaleModeAlign {
+	/** Anchor Scene viewport horizontally to left side of the window. When passed to verticalAlign it will be treated as Center. **/
+	Left;
+	/** Anchor Scene viewport horizontally to right side of the window. When passed to verticalAlign it will be treated as Center. **/
+	Right;
+	/** Anchor to the center of window. **/
+	Center;
+	/** Anchor Scene viewport vertically to the top of a window. When passed to horizontalAlign it will be treated as Center. **/
+	Top;
+	/** Anchor Scene viewport vertically to the bottom of a window. When passed to horizontalAlign it will be treated as Center. **/
+	Bottom;
+}
+
+/**
+	Scaling mode of the 2D Scene.  
+	See `ScaleMode2D` sample for showcase.
+**/
+enum ScaleMode {
+
+	/**
+		Matches scene size to window size. `width` and `height` of Scene will match window size. Default scaling mode.
+	**/
+	Resize;
+
+	/**
+		Sets constant Scene size and stretches it to cover entire window. This behavior is same as old `setFixedSize` method.
+	**/
+	Stretch(width : Int, height : Int);
+
+	/**
+		Sets constant scene size and upscales it with preserving aspect-ratio to fit the window.  
+		If `integerScale` is `true` - scaling will be performed  with only integer increments (1x, 2x, 3x, ...). Default: `false`  
+		`horizontalAlign` controls viewport anchoring horizontally. Accepted values are `Left`, `Center` and `Right`. Default: `Center`  
+		`verticalAlign` controls viewport anchoring vertically. Accepted values are `Top`, `Center` and `Bottom`. Default: `Center`  
+		With `800x600` window, `LetterBox(320, 260)` will result in center-aligned Scene of size `320x260` upscaled to fit into screen.
+	**/
+	LetterBox(width : Int, height : Int, ?integerScale : Bool, ?horizontalAlign : ScaleModeAlign, ?verticalAlign : ScaleModeAlign);
+
+	/**
+		Sets constant Scene size, scale and alignment. Does not perform any adaptation to the screen apart from alignment.
+		`horizontalAlign` controls viewport anchoring horizontally. Accepted values are `Left`, `Center` and `Right`. Default: `Center`  
+		`verticalAlign` controls viewport anchoring vertically. Accepted values are `Top`, `Center` and `Bottom`. Default: `Center`  
+		With `800x600` window, `Fixed(200, 150, 2, Left, Center)` will result in Scene size of `200x150`, and visually upscaled to `400x300`, and aligned to middle-left of the window.
+	**/
+	Fixed(width : Int, height: Int, zoom : Float, ?horizontalAlign : ScaleModeAlign, ?verticalAlign : ScaleModeAlign);
+
+	/**
+		Upscales/downscales Scene according to `level` and matches Scene size to `ceil(window size / level)`.  
+		With `800x600` window, `Zoom(2)` will result in `400x300` Scene size upscaled to fill entire window.
+	**/
+	Zoom(level : Float);
+
+	/**
+		Ensures that Scene size will be of minimum specified size.  
+		Automatically calculates zoom level based on provided size according to `min(window width / min width, window height / min height)`, then applies same scaling as `Zoom(level)`.
+		Behavior is similiar to LetterBox, however instead of letterboxing effect, Scene size will change to cover the letterboxed parts.  
+		`minWidth` or `minHeight` can be set to `0` in order to force scaling adjustment account only for either horizontal of vertical window size.  
+		If `integerScale` is `true` - scaling will be performed  with only integer increments (1x, 2x, 3x, ...). Default: `false`  
+		With `800x600` window, `AutoZoom(320, 260, false)` will result in Scene size of `347x260`. `AutoZoom(320, 260, true)` will result in size of `400x300`.
+	**/
+	AutoZoom(minWidth : Int, minHeight : Int, ?integerScaling : Bool);
+}
+
 /**
 /**
 	h2d.Scene is the root class for a 2D scene. All root objects are added to it before being drawn on screen.
 	h2d.Scene is the root class for a 2D scene. All root objects are added to it before being drawn on screen.
 **/
 **/
 class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.InteractiveScene {
 class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.InteractiveScene {
 
 
 	/**
 	/**
-		The current width (in pixels) of the scene. Can change if the screen gets resized.
+		The current width (in pixels) of the scene. Can change if the screen gets resized or `scaleMode` changes.
 	**/
 	**/
 	public var width(default,null) : Int;
 	public var width(default,null) : Int;
 
 
 	/**
 	/**
-		The current height (in pixels) of the scene. Can change if the screen gets resized.
+		The current height (in pixels) of the scene. Can change if the screen gets resized or `scaleMode` changes.
 	**/
 	**/
 	public var height(default, null) : Int;
 	public var height(default, null) : Int;
 
 
+	/**
+		Horizontal viewport offset relative to top-left corner of the window. Can change if the screen gets resized or `scaleMode` changes.  
+		Offset is in internal Scene resolution pixels.
+	**/
+	public var viewportX(default, null) : Float;
+	/**
+		Vertical viewport offset relative to top-left corner of the window. Can change if the screen gets resized or `scaleMode` changes.  
+		Offset is in internal Scene resolution pixels.
+	**/
+	public var viewportY(default, null) : Float;
+	/**
+		Physical vertical viewport offset relative to the center of the window. Assigned if the screen gets resized or `scaleMode` changes.  
+		Offset is in internal Scene resolution pixels.
+	**/
+	public var offsetX : Float;
+	/**
+		Physical horizontal viewport offset relative to the center of the window. Assigned if the screen gets resized or `scaleMode` changes.  
+		Offset is in internal Scene resolution pixels.
+	**/
+	public var offsetY : Float;
+
+	/**
+		Horizontal ratio of the window used by the Scene (including scaling). Can change if the screen gets resized or `scaleMode` changes.
+	**/
+	public var ratioX(default, null) : Float;
+	/**
+		Vertical ratio of the window used by the Scene (including scaling). Can change if the screen gets resized or `scaleMode` changes.
+	**/
+	public var ratioY(default, null) : Float;
+
 	/**
 	/**
 		The current mouse X coordinates (in pixel) relative to the scene.
 		The current mouse X coordinates (in pixel) relative to the scene.
 	**/
 	**/
@@ -30,7 +126,16 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		The zoom factor of the scene, allows to set a fixed x2, x4 etc. zoom for pixel art
 		The zoom factor of the scene, allows to set a fixed x2, x4 etc. zoom for pixel art
 		When setting a zoom > 0, the scene resize will be automaticaly managed.
 		When setting a zoom > 0, the scene resize will be automaticaly managed.
 	**/
 	**/
-	public var zoom(default, set) : Int = 0;
+	@:deprecated("zoom is deprecated, use scaleMode = Zoom(v) instead")
+	public var zoom(get, set) : Int;
+
+	/**
+		Scene scaling mode. ( default : Fill )
+		Important thing to keep in mind - Scene does not clip rendering to it's scaled size and
+		graphics can render outside of it. However `drawTile` does check for those bounds and 
+		will clip out tiles that are outside of the scene bounds.
+	**/
+	public var scaleMode(default, set) : ScaleMode = Resize;
 
 
 	/**
 	/**
 		Set the default value for `h2d.Drawable.smooth` (default: false)
 		Set the default value for `h2d.Drawable.smooth` (default: false)
@@ -42,7 +147,6 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 	**/
 	**/
 	public var renderer(get, set) : RenderContext;
 	public var renderer(get, set) : RenderContext;
 
 
-	var fixedSize : Bool;
 	var interactive : Array<Interactive>;
 	var interactive : Array<Interactive>;
 	var eventListeners : Array< hxd.Event -> Void >;
 	var eventListeners : Array< hxd.Event -> Void >;
 	var ctx : RenderContext;
 	var ctx : RenderContext;
@@ -60,6 +164,12 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		ctx = new RenderContext(this);
 		ctx = new RenderContext(this);
 		width = e.width;
 		width = e.width;
 		height = e.height;
 		height = e.height;
+		offsetX = 0;
+		offsetY = 0;
+		ratioX = 1;
+		ratioY = 1;
+		viewportX = 0;
+		viewportY = 0;
 		interactive = new Array();
 		interactive = new Array();
 		eventListeners = new Array();
 		eventListeners = new Array();
 		shapePoint = new h2d.col.Point();
 		shapePoint = new h2d.col.Point();
@@ -75,17 +185,22 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 		this.events = events;
 		this.events = events;
 	}
 	}
 
 
+	function get_zoom() : Int {
+		return switch ( scaleMode ) {
+			case Zoom(level): Std.int(level);
+			default: 0;
+		}
+	}
+
 	function set_zoom(v:Int) {
 	function set_zoom(v:Int) {
-		var e = h3d.Engine.getCurrent();
-		var twidth = Math.ceil(window.width / v);
-		var theight = Math.ceil(window.height / v);
-		var totalWidth = twidth * v;
-		var totalHeight = theight * v;
-		// increase back buffer size if necessary
-		if( totalWidth != e.width || totalHeight != e.height )
-			e.resize(totalWidth, totalHeight);
-		setFixedSize(twidth, theight);
-		return zoom = v;
+		scaleMode = Zoom(v);
+		return v;
+	}
+
+	function set_scaleMode( v : ScaleMode ) {
+		scaleMode = v;
+		checkResize();
+		return v;
 	}
 	}
 
 
 	function get_renderer() return ctx;
 	function get_renderer() return ctx;
@@ -94,32 +209,109 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 	/**
 	/**
 		Set the fixed size for the scene, will prevent automatic scene resizing when screen size changes.
 		Set the fixed size for the scene, will prevent automatic scene resizing when screen size changes.
 	**/
 	**/
+	@:deprecated("setFixedSize is deprecated, use scaleMode = Strech(w, h) instead")
 	public function setFixedSize( w : Int, h : Int ) {
 	public function setFixedSize( w : Int, h : Int ) {
-		width = w;
-		height = h;
-		fixedSize = true;
-		posChanged = true;
+		scaleMode = Stretch(w, h);
 	}
 	}
 
 
 	@:dox(hide) @:noCompletion
 	@:dox(hide) @:noCompletion
 	public function checkResize() {
 	public function checkResize() {
-		if( fixedSize && zoom == 0 ) return;
 		var engine = h3d.Engine.getCurrent();
 		var engine = h3d.Engine.getCurrent();
-		var scale = zoom == 0 ? 1 : zoom;
-		if( width * scale != engine.width || height * scale != engine.height ) {
-			width = engine.width;
-			height = engine.height;
-			posChanged = true;
-			if( zoom != 0 ) this.zoom = zoom;
+
+		inline function setSceneSize( w : Int, h : Int ) {
+			if ( w != this.width || h != this.height ) {
+				width = w;
+				height = h;
+				posChanged = true;
+			}
+		}
+
+		inline function calcRatio( scale : Float ) {
+			ratioX = (width * scale) / engine.width;
+			ratioY = (height * scale) / engine.height;
+		}
+
+		inline function calcViewport( horizontal : ScaleModeAlign, vertical : ScaleModeAlign, zoom : Float ) {
+			if ( horizontal == null ) horizontal = Center;
+			switch ( horizontal ) {
+				case Left:
+					offsetX = (engine.width - width * zoom) / (2 * zoom);
+					viewportX = 0;
+				case Right:
+					offsetX = -((engine.width - width * zoom) / (2 * zoom));
+					viewportX = (engine.width - width * zoom) / zoom;
+				default:
+					offsetX = 0;
+					viewportX = (engine.width - width * zoom) / (2 * zoom);
+			}
+
+			if ( vertical == null ) vertical = Center;
+			switch ( vertical ) {
+				case Top:
+					offsetY = (engine.height - height * zoom) / (2 * zoom);
+					viewportY = 0;
+				case Bottom:
+					offsetY = -((engine.height - height * zoom) / (2 * zoom));
+					viewportY = (engine.height - height * zoom) / zoom;
+				default:
+					offsetY = 0;
+					viewportY = (engine.height - height * zoom) / (2 * zoom);
+			}
+		}
+
+		inline function zeroViewport() {
+			offsetX = 0;
+			offsetY = 0;
+			viewportX = 0;
+			viewportY = 0;
+		}
+
+		switch ( scaleMode ) {
+			case Resize:
+				setSceneSize(engine.width, engine.height);
+				ratioX = 1;
+				ratioY = 1;
+				zeroViewport();
+			case Stretch(_width, _height):
+				setSceneSize(_width, _height);
+				ratioX = 1;
+				ratioY = 1;
+				zeroViewport();
+			case LetterBox(_width, _height, integerScale, horizontalAlign, verticalAlign):
+				setSceneSize(_width, _height);
+				var zoom = Math.min(engine.width / _width, engine.height / _height);
+				if ( integerScale ) {
+					zoom = Std.int(zoom);
+					if (zoom == 0) zoom = 1;
+				}
+				calcRatio(zoom);
+				calcViewport(horizontalAlign, verticalAlign, zoom);
+			case Fixed(_width, _height, zoom, horizontalAlign, verticalAlign):
+				setSceneSize(_width, _height);
+				calcRatio(zoom);
+				calcViewport(horizontalAlign, verticalAlign, zoom);
+			case Zoom(level):
+				setSceneSize(Math.ceil(engine.width / level), Math.ceil(engine.height / level));
+				calcRatio(level);
+				zeroViewport();
+			case AutoZoom(minWidth, minHeight, integerScaling):
+				var zoom = Math.min(engine.width / minWidth, engine.height / minHeight);
+				if ( integerScaling ) {
+					zoom = Std.int(zoom);
+					if ( zoom == 0 ) zoom = 1;
+				}
+				setSceneSize(Math.ceil(engine.width / zoom), Math.ceil(engine.height / zoom));
+				calcRatio(zoom);
+				zeroViewport();
 		}
 		}
 	}
 	}
 
 
 	inline function screenXToLocal(mx:Float) {
 	inline function screenXToLocal(mx:Float) {
-		return mx * width / (window.width * scaleX) - x;
+		return mx * width / (window.width * ratioX * scaleX) - x - viewportX;
 	}
 	}
 
 
 	inline function screenYToLocal(my:Float) {
 	inline function screenYToLocal(my:Float) {
-		return my * height / (window.height * scaleY) - y;
+		return my * height / (window.height * ratioY * scaleY) - y - viewportY;
 	}
 	}
 
 
 	function get_mouseX() {
 	function get_mouseX() {
@@ -497,10 +689,22 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 	override function sync( ctx : RenderContext ) {
 	override function sync( ctx : RenderContext ) {
 		if( !allocated )
 		if( !allocated )
 			onAdd();
 			onAdd();
-		checkResize();
 		super.sync(ctx);
 		super.sync(ctx);
 	}
 	}
 
 
+	override function onAdd()
+	{
+		checkResize();
+		super.onAdd();
+		window.addResizeEvent(checkResize);
+	}
+
+	override function onRemove()
+	{
+		super.onRemove();
+		window.removeResizeEvent(checkResize);
+	}
+
 	/**
 	/**
 		Capture the scene into a texture and render the resulting Bitmap
 		Capture the scene into a texture and render the resulting Bitmap
 	**/
 	**/
@@ -515,14 +719,28 @@ class Scene extends Layers implements h3d.IDrawable implements hxd.SceneEvents.I
 
 
 		var tex = target.getTexture();
 		var tex = target.getTexture();
 		engine.pushTarget(tex);
 		engine.pushTarget(tex);
-		var ow = width, oh = height, of = fixedSize;
-		setFixedSize(tex.width, tex.height);
+		var ow = width, oh = height, ox = offsetX, oy = offsetY;
+		var ovx = viewportX, ovy = viewportY, orx = ratioX, ory = ratioY;
+		width = tex.width;
+		height = tex.height;
+		ratioX = 1;
+		ratioY = 1;
+		offsetX = 0;
+		offsetY = 0;
+		viewportX = 0;
+		viewportY = 0;
+		posChanged = true;
 		render(engine);
 		render(engine);
 		engine.popTarget();
 		engine.popTarget();
 
 
 		width = ow;
 		width = ow;
 		height = oh;
 		height = oh;
-		fixedSize = of;
+		ratioX = orx;
+		ratioY = ory;
+		offsetX = ox;
+		offsetY = oy;
+		viewportX = ovx;
+		viewportY = ovy;
 		posChanged = true;
 		posChanged = true;
 		engine.setRenderZone();
 		engine.setRenderZone();
 		engine.end();
 		engine.end();

+ 77 - 0
samples/ScaleMode2D.hx

@@ -0,0 +1,77 @@
+import hxd.Key;
+import h2d.Scene;
+
+class ScaleMode2D extends SampleApp {
+
+	override function init()
+	{
+
+		var bg = new h2d.Bitmap(h2d.Tile.fromColor(0x333333), s2d);
+		var minBg = new h2d.Bitmap(h2d.Tile.fromColor(0x222222), s2d);
+
+		super.init();
+
+		var mode:Int = 0;
+		// Width and height used in Stretch, LetterBox, Fixed and AutoZoom
+		var width:Int = 320;
+		var height:Int = 240;
+		// Zoom used in Fixed and Zoom
+		var zoom:Float = 1;
+		// Integer Scale used in LetterBox and AutoZoom
+		var intScale:Bool = false;
+		// Vertical and Horizontal Align used in LetterBox and Fixed.
+		var halign:ScaleModeAlign = Center;
+		var valign:ScaleModeAlign = Center;
+
+		var sceneInfo:h2d.Text;
+
+		function setMode()
+		{
+			switch ( mode ) {
+				case 0:
+					s2d.scaleMode = Resize;
+				case 1:
+					s2d.scaleMode = Stretch(width, height);
+				case 2:
+					s2d.scaleMode = LetterBox(width, height, intScale, halign, valign);
+				case 3:
+					s2d.scaleMode = Fixed(width, height, zoom, valign, halign);
+				case 4:
+					s2d.scaleMode = Zoom(zoom);
+				case 5:
+					s2d.scaleMode = AutoZoom(width, height, intScale);
+			}
+			minBg.scaleX = width;
+			minBg.scaleY = height;
+			bg.scaleX = s2d.width;
+			bg.scaleY = s2d.height;
+			sceneInfo.text = "Scene size: " + s2d.width + "x" + s2d.height;
+		}
+
+		addText("Press R to set ScaleMode to Resize");
+		addChoice("ScaleMode", ScaleMode.getConstructors(), function(idx) { mode = idx; }, 0);
+		addSlider("width", function() { return width; }, function(v) { width = Std.int(v); }, 0, 800);
+		addSlider("height", function() { return height; }, function(v) { height = Std.int(v); }, 0, 600);
+		addSlider("zoom", function() { return zoom; }, function(v) { zoom = v; }, 0.01, 5);
+		addCheck("integerScale", function() { return intScale; }, function(v) { intScale = v; });
+		addChoice("HAlign", ["Left", "Center", "Right"], function(v) { halign = [Left, Center, Right][v]; }, 1 );
+		addChoice("VAlign", ["Top", "Center", "Bottom"], function(v) { valign = [Top, Center, Bottom][v]; }, 1 );
+		addButton("Apply", setMode);
+		sceneInfo = addText("");
+		addText("Light-grey: Actual Scene width and height");
+		addText("Dark-grey: Parameter-specified width and height");
+
+		setMode();
+	}
+
+	override function update(dt:Float)
+	{
+		if (Key.isReleased(Key.R)) s2d.scaleMode = Resize;
+	}
+
+	static function main() {
+		hxd.Res.initEmbed();
+		new ScaleMode2D();
+	}
+
+}