Last active
January 2, 2016 19:09
-
-
Save nobuyukinyuu/8348382 to your computer and use it in GitHub Desktop.
Automatic scaling and letterboxing, plus matrix-compensated cursor and scissor functions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'Copyright 2011-2014 Nobuyuki (nobu[AT]subsoap.com). | |
'No warranties expressed or implied. | |
Import mojo | |
Private | |
Global lastDeviceWidth:Float, lastDeviceHeight:Float | |
Public | |
Global PreserveAspectRatio:Bool = True 'Aspect ratio preserving | |
Global ScreenWidth:Float = 800 'Native size of your app | |
Global ScreenHeight:Float = 480 | |
Global ScaleFactor:Float 'Amount to scale window by preserving aspect ratio; calculated at runtime | |
Global SlideAxis:Bool '0: X-Axis, 1: Y-Axis | |
Global SlideAmount:Int 'amount to slide the window to center the screen | |
Global ScaleX:Float, ScaleY:Float 'Individual scale amounts for sloppy stretch to window | |
Function initAutoScale:Void(w:Float = 800, h:Float = 480, preserveAspectRatio:Bool = True) | |
ScreenWidth = w; ScreenHeight = h; PreserveAspectRatio = preserveAspectRatio | |
lastDeviceWidth = DeviceWidth(); lastDeviceHeight = DeviceHeight() | |
ScaleX = DeviceWidth() / ScreenWidth | |
ScaleY = DeviceHeight() / ScreenHeight | |
'shorter distance determines scale factor | |
If ScaleX < ScaleY then ScaleFactor = ScaleX else ScaleFactor = ScaleY | |
'calculate slide distance based on derived size | |
Local DiffX:Int= DeviceWidth() - ScreenWidth * ScaleFactor | |
Local DiffY:Int= DeviceHeight() - ScreenHeight * ScaleFactor | |
If ScaleX < ScaleY then | |
SlideAxis = True 'Set axis to Y | |
SlideAmount = DiffY / 2 | |
else | |
SlideAxis = False 'Set axis to X | |
SlideAmount = DiffX / 2 | |
End if | |
'Scale the slide amount by the scale factor to get the real slide amount after scaling | |
SlideAmount *= (1/ScaleFactor) | |
End Function | |
Function CheckScreenDimensions:Void() | |
If lastDeviceWidth <> DeviceWidth() Or lastDeviceHeight <> DeviceHeight() Then | |
initAutoScale(ScreenWidth, ScreenHeight, PreserveAspectRatio) | |
'Print "Screen dimensions changed. " + lastDeviceWidth + "=" + DeviceWidth() + ", " + | |
' lastDeviceHeight + "=" + DeviceHeight() | |
End If | |
End Function | |
'Summary: Scales the screen. It is recommended that you call this at beginning of OnRender. | |
Function ScaleScreen:Void(checkForResize:Bool = True) | |
If checkForResize = True Then CheckScreenDimensions() | |
'SetMatrix (1,0,0,1,0,0) 'Identity Matrix | |
If PreserveAspectRatio = True Then | |
Scale(ScaleFactor, ScaleFactor) | |
If SlideAxis = False Then Translate(SlideAmount, 0) Else Translate(0, SlideAmount) | |
Else | |
Scale(ScaleX, ScaleY) | |
End If | |
End Function | |
'Derived mouse positions | |
Function dMouseX:Int() | |
If PreserveAspectRatio | |
If SlideAxis = False Then Return MouseX() / ScaleFactor - SlideAmount Else Return MouseX() / ScaleFactor | |
Else | |
Return MouseX() / ScaleX | |
End If | |
End Function | |
Function dMouseY:Int() | |
If PreserveAspectRatio | |
If SlideAxis = True Then Return MouseY() / ScaleFactor - SlideAmount Else Return MouseY() / ScaleFactor | |
Else | |
Return MouseY() / ScaleY | |
End If | |
End Function | |
'Derived multitouch positions | |
Function dTouchX:Int(index:Int=0) | |
If PreserveAspectRatio | |
If SlideAxis = False Then Return TouchX(index) / ScaleFactor - SlideAmount Else Return TouchX(index) / ScaleFactor | |
Else | |
Return TouchX(index) / ScaleX | |
End If | |
End Function | |
Function dTouchY:Int(index:Int=0) | |
If PreserveAspectRatio | |
If SlideAxis = True Then Return TouchY(index) / ScaleFactor - SlideAmount Else Return TouchY(index) / ScaleFactor | |
Else | |
Return TouchY(index) / ScaleY | |
End If | |
End Function | |
'Derived device screen positions. Returns position based on percent from 0-1. | |
Function DeviceX:Float(percent:Float=1) | |
If ScaleX = 1 Then Return DeviceWidth() * percent | |
If SlideAxis = False Then Return (DeviceWidth() / ScaleFactor) * percent - SlideAmount Else Return (DeviceWidth()/ScaleFactor) * percent | |
End Function | |
Function DeviceY:Float(percent:Float=1) | |
If ScaleY = 1 Then Return DeviceHeight() * percent | |
If SlideAxis = True Then Return (DeviceHeight() / ScaleFactor) * percent - SlideAmount Else Return (DeviceHeight()/ScaleFactor) * percent | |
End Function | |
'Derived Scissor | |
Function SetScaledScissor:Void(x:Float, y:Float, width:Float, height:Float) | |
Local sx:Float, sy:Float | |
If PreserveAspectRatio = True Then | |
If SlideAxis = False Then sx = (x + SlideAmount) * ScaleFactor Else sx = x * ScaleFactor | |
If SlideAxis = True Then sy = (y + SlideAmount) * ScaleFactor Else sy = y * ScaleFactor | |
SetScissor(sx, sy, ScaleFactor * width, ScaleFactor * height) | |
Else | |
sx = x * ScaleX | |
sy = y * ScaleY | |
SetScissor(sx, sy, ScaleX * width, ScaleY * height) | |
End If | |
End Function | |
'Summary: Renders a letterbox over the top of the surface. | |
Function RenderLetterBox:Void(lb:LetterBoxer) | |
If DeviceWidth() = ScreenWidth And DeviceHeight() = ScreenHeight Then Return | |
Local x:Float, y:Float, w:Float, h:Float | |
If SlideAxis = False Then 'X-Axis | |
w = SlideAmount * ScaleFactor 'Letterbox size | |
h = DeviceHeight() | |
x = DeviceWidth() -w 'SideB origin | |
Else 'Y-Axis | |
w = DeviceWidth() | |
h = SlideAmount * ScaleFactor | |
y = DeviceHeight() -h 'SideB origin | |
End If | |
SetMatrix(1, 0, 0, 1, 0, 0) 'Identity matrix. | |
lb.Render(0, 0, w, h, False) | |
lb.Render(x, y, Ceil(w), Ceil(h), True) 'Side B | |
End Function | |
'Summary: Base LetterBoxer class. Extend this with your own to make custom letterboxes. | |
Class LetterBoxer Abstract | |
Method Render:Void(x:Float, y:Float, w:Float, h:Float, SideB:Bool = False) Abstract | |
End Class | |
'Summary: The most basic type of letterbox; colored bars. | |
Class ColoredLetterBox Extends LetterBoxer | |
Field r:Int, g:Int, b:Int | |
Method New(r:Int, g:Int, b:Int) | |
Self.r = r; Self.g = g; Self.b = b | |
End Method | |
Method Render:Void(x:Float, y:Float, w:Float, h:Float, SideB:Bool) | |
SetColor(r, g, b) | |
DrawRect(x, y, w, h) | |
SetColor(255, 255, 255) | |
End Method | |
End Class | |
'Summary: Displays an image on either side of the letterbox. | |
Class BookEndLetterBox Extends LetterBoxer | |
Field img:Image, img2:Image | |
Method New(A:Image, B:Image) | |
img = A; img2 = B | |
End Method | |
Method Render:Void(x:Float, y:Float, w:Float, h:Float, SideB:Bool) | |
If SideB | |
DrawImage(img2, x, y, 0, w / img2.Width, h / img2.Height) | |
Else | |
DrawImage(img, x, y, 0, w / img.Width, h / img.Height) | |
End If | |
End Method | |
End Class | |
'Summary: Displays a tiled image on both sides of the letterbox. | |
Class TiledLetterBox Extends LetterBoxer | |
Field img:Image | |
Method New(img:Image) | |
Self.img = img | |
End Method | |
Method Render:Void(x:Float, y:Float, w:Float, h:Float, SideB:Bool) | |
Local s:Float[] = GetScissor() | |
SetScissor(x, y, w, h) | |
For Local yy:Int = 0 To Ceil(h / img.Height) | |
For Local xx:Int = 0 To Ceil(w / img.Width) | |
DrawImage(img, x + xx * img.Width, y + yy * img.Height) | |
Next | |
Next | |
SetScissor(s[0], s[1], s[2], s[3]) | |
End Method | |
End Class |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment