AutoFit (update)

Monkey Forums/Monkey Code/AutoFit (update)

DruggedBunny(Posted 2011) [#1]
Here's an update to my AutoFit example from the Monkey distribution, which scales a fixed virtual display size to the current device size, adding black borders where needed, taking aspect ratio into account.

http://www.hi-toro.com/monkey/autofit/autofit.zip

The old version recalculated pretty much everything on every update; now it just does a few checks and recalculates only when the device or zoom level has changed, something I've meant to sort out for ages. This is the new typical codepath (after the first call):

Method UpdateVirtualDisplay (zoomborders:Bool, keepborders:Bool)

	If (DeviceWidth <> lastdevicewidth)...			' Early out here and nothing to do...
	If device_changed...					' Nothing to do here...
	If vzoom <> lastvzoom...				' Nothing to do here...
	If zoom_changed Or device_changed...			' Nothing to do here...

	SetScissor 0, 0, DeviceWidth, DeviceHeight		' Set outer border...
	Cls 0, 0, 0			'			' Clear to black...

	SetScissor sx, sy, sw, sh				' Set inner area...
	Scale multi * vzoom, multi * vzoom			' Set scale to fit...

	If vzoom Then Translate vxoff, vyoff			' Always called unless zoom is zero...
	
End


It's been tested on HTML5, Flash, GLFW, XNA (Windows) and Android (SDK emulator).

Finally, here's a realtime capture of the new code applied to an existing game (using AutoFit) with no changes required, in the slow Android emulator:

http://www.youtube.com/watch?v=I4XQhsvnLfw

(Device rotates at 00:05, change detected by device a second later, then display updates to adapt. Changes back at 00:13.)


c.k.(Posted 2011) [#2]
Well done, DB! :)


DruggedBunny(Posted 2011) [#3]
Here's a stripped-down demo that shows how you can treat a virtual resolution as if it's a fixed display size and simply hard-code your positions for that display size if you want to:




GfK(Posted 2011) [#4]
Cool. im using the older version for crime solitaire so ill update tomorrow.


DruggedBunny(Posted 2011) [#5]
Excellent -- it should just drop in with no side effects, hopefully.


Difference(Posted 2011) [#6]
Marvelous, - dropped it right in and it works great!


GfK(Posted 2011) [#7]
Just tried this in 1.45b - I'm assuming it'll work but there are shedloads of errors when compiled in Strict mode.


slenkar(Posted 2011) [#8]
it has virtual mouse coords too, thanks!


DruggedBunny(Posted 2011) [#9]
@Gfk, sorry, I'll sort that... I'm really surprised I didn't use SuperStrict, but you're right, I didn't!

@Slenkar: yeah, I'll probably add the Touch* stuff as well.


DruggedBunny(Posted 2011) [#10]
OK, I've updated AutoFit so that the module is now Strict, and added VTouchX/Y calls too, plus the simpler demo above:

http://www.hi-toro.com/monkey/autofit/autofit.zip

Don't know why I was rambling on about SuperStrict, since Monkey doesn't have it -- mustn't post while hung over. However, I've realised that I don't use Strict in Monkey because of the forced returns values/function types, etc -- non-Strict catches undeclared variables anyway, which is what I mainly want.


DarkyCrystal(Posted 2011) [#11]
Good job. So if I understand it's better to work with high resolution to avoid black borders ? On a phone graph could be more small.


DruggedBunny(Posted 2011) [#12]
No, the black borders only appear if your 'virtual' resolution's aspect ratio doesn't match that of the device's real display.

For example, a 320 x 240 display, a 640 x 480 display and an 800 x 600 display all share a 4:3 aspect ratio (width:height). If you set your virtual resolution to 640 x 480, and the game runs on a device with 320, 640 or 800 resolutions, there will be no borders.

If you run that game on a device with a 16:9 display (eg. 1920 x 1080), because the aspect ratios don't match, you use black borders to show the game at its 4:3 aspect ratio within the 16:9 display.

In short, you choose what aspect ratio your game is going to use via your choice of virtual resolution, and the game will automatically adapt to the aspect ratio of any display it finds itself running on, using the full width or height of the display available while maintaining your chosen aspect ratio.

Hope that makes sense!


siread(Posted 2011) [#13]
Is it possible to lock the screen orientation? I only ever want my game to display in portrait view, and not switch to landscape (with borders) when the device is tilted (although I don't mind it flipping if the device is turned 180 degrees).


GfK(Posted 2011) [#14]
Is it possible to lock the screen orientation? I only ever want my game to display in portrait view, and not switch to landscape (with borders) when the device is tilted (although I don't mind it flipping if the device is turned 180 degrees).
That's target-specific. For iOS, you'll need to open up XCode, where you'll have the option to lock screen orientation, set icons, choose ARM6/7 architecture and so on. Oh, and don't forget to switch off Debug build, which is ON by default.

I know you can do the same stuff in Android but having never used it, I don't know how.


therevills(Posted 2011) [#15]
I know you can do the same stuff in Android but having never used it, I don't know how.


Just set the option in the AndroidManifest... with Monkey you can just alter the config text file :)

'Must be one of: user, portrait, langscape, behind, sensor, nosensor, unspecified - experiment!
SCREEN_ORIENTATION=landscape



siread(Posted 2011) [#16]
Cheers. :)


NoOdle(Posted 2011) [#17]
DruggedBunny you rock!

This is perfect, drops straight in to my framework. Works perfectly on IOS as well, you can rotate the device from the menu like on Android and it resizes to fit. Saved me a huge headache and quite a few hours of hell.

I owe you some drugs sir! ;)


slenkar(Posted 2012) [#18]
on android you have to set the screen orientation to 'user'
to make the game rotate when turn the android device?


Volker(Posted 2012) [#19]
Try 'sensor'.


siread(Posted 2012) [#20]
I added a method to the VirtualDisplay class that allows you to use scissors on your scaled display. Took me bloody ages to get my head around it but it seems to work. :)

	Method SetVScissor:Int (vsx:Float, vsy:Float, vsw:Float, vsh:Float)
		' Allows you to set up a scissor on a scaled display
		' Call UnsetVScissor when you want to continue drawing outside of the scissor area
		
		Local sclx:Float = scaledw / vwidth
		Local scly:Float = scaledh / vheight
		
		Local vscissor:Float[4]
		
		vscissor[0] = Max(sx, sx + (vsx * sclx))
		vscissor[1] = Max(sy, sy + (vsy * scly))
		vscissor[2] = vsw * sclx
		vscissor[3] = vsh * scly
		
		If vscissor[0] + vscissor[2] > scaledw Then vscissor[2] = (sx + scaledw) - vscissor[0]
		If vscissor[1] + vscissor[3] > scaledh Then vscissor[3] = (sy + scaledh) - vscissor[1]
		
		SetScissor(vscissor[0], vscissor[1], vscissor[2], vscissor[3])
		
		Return 0
	End
	
	Method UnsetVScissor:Int ()
		SetScissor sx, sy, sw, sh
		
		Return 0
	End



Foppy(Posted 2012) [#21]
Thanks for this wonderful module.

I had uploaded my Doggy Bounce game to Google Play, only to notice that on a friend's phone it went outside of the screen. I had completely forgotten about different resolutions, thinking that it would somehow be scaled automatically.

With Autofit I just had to add two lines of code to the program, and change one call to TouchX() to VTouchX(), and now it does work perfectly, at least on mine and that other phone! :D


DruggedBunny(Posted 2012) [#22]
Cool... I feel like Doc Brown hearing that others are making use of this in the real-world: "It works! I finally invented something that works!"


fsoft(Posted 2012) [#23]
DruggedBunny ... it works great, actually ;-)


Chroma(Posted 2013) [#24]
Cool, thanks for this. Getting closer and closer to my first mobile game release!


bram(Posted 2013) [#25]
Nice work, saves a lot of headaches. Thank you for sharing this.


Supertino(Posted 2013) [#26]
Well I was coming here to enquirer about using scissors on a scaled display and it seems that siread has come up with a solution. yippee.

As always a big THANKYOU to James Boyd for autofit and a hearty handshake to sired, though I am sure sired is too busy mixing with his new high end dev friends and driving around in one of his many sports cars to care :p


DruggedBunny(Posted 2013) [#27]
I was actually going to update it with Si's scissor stuff a while ago... will do soon-ish!


Sammy(Posted 2013) [#28]
Just test out this module, looks great but I am having a little trouble.

Just for testing purposes I set up a virtual display of 1280x720 but noticed that the first line of the virtual display was intermittently not being displayed. I assumed that this was just due to the physical screen resolution not matching the virtual one. So I set the virtual screen to match the physical one, so it should not really be scaling and yet the first line is still missing?

This does not draw a rectangle:-

DrawLine(0, 0, 1279, 0)
DrawLine(0, 719, 1279, 719)
DrawLine(0, 0, 0, 719)
DrawLine(1279, 0, 1279, 719)

This does? :-

DrawLine(0, 1, 1279, 1)
DrawLine(0, 719, 1279, 719)
DrawLine(0, 0, 0, 719)
DrawLine(1279, 0, 1279, 719)

It's not a big deal but it may be indicative of a bug.


RENGAC(Posted 2013) [#29]
Hi! It's possible to "stretch" the virtual canvas to fill the screen, even if it means to lose the aspect ratio?


Sensei(Posted 2013) [#30]
Just wanted to say a huge thanks to @druggedbunny for this awesome piece of code. I initially tried doing my own thing, which worked, but it was nowhere near as elegant as this. Thank you for making my life easier :)
The screen rotate and scale changes are simply a godsend.


Snader(Posted 2013) [#31]
Yeah, autofit rocks! I would like to see a possibility to stretch the virtual canvas if, for example, the black border only takes 5% of the total deviceheight or devicewidth. It will lose the aspect ratio, but not much.


Loofadawg(Posted 2013) [#32]
How do I get rid of artifacts from Autofit?



If you look at the arrow - between the squares is a red line. It is as if the images bleed through.

The second image is with Autofit turned off, and voila.. no more artifacts.


The images are 64x64 and the horizontal / vertical parameter for Autofit is 512 / 768.

I am guessing it has a lot to do with the ratio. But where does the red come from? The neighboring image from the file contains red, but it shouldn't bleed into the other image should it? I changed the image to cyan and sure enough the red becomes cyan.

The image file itself is 28 64x64 going 7 across and 4 deep.


Again.. When I disable Autofit, it goes away.


therevills(Posted 2013) [#33]
Could you try defringing the image? Download DeFringe app from here:
https://sites.google.com/site/yanbloke/


Loofadawg(Posted 2013) [#34]
Not sure what DeFringe is but the the site is currently down. :(


I am going to write some code up in a bit to hopefully load up the "sprite sheet" image and cut it up into the 64x64 pieces and stick them in an array and see if that helps.


Loofadawg(Posted 2013) [#35]
We ( or maybe just *I* ) need a FAQ for Monkey. It appears this type of thing has been discussed many times.. just buried deep in the forums. :)


Nobuyuki(Posted 2013) [#36]
Be sure to pad the images, edge fringe is often the result of the bilinear filtering process grabbing pixels from beyond the borders of the texture being displayed and processing them into the end result you see on screen. AutoFit doesn't actually do this, the hardware does. There are multiple solutions to the problem, but probably the easiest (and with least impact on performance) is to simply pad the image.

Now, gaps in tiles is another matter, there are a bunch of problems/solutions for that, depending on whether you need alpha accuracy....


Loofadawg(Posted 2013) [#37]
Nobuyuki and therevills, Thank you both for your help.


Raul(Posted 2013) [#38]
question:
in the last 'autofit' file I observed the GetMultiratio it is missing. i needed that function for my calculations.

why did you delete that function?


DruggedBunny(Posted 2013) [#39]
@Raul: I think that might be in Nobuyuki's AutoScale -- it was never in AutoFit anyway!


Raul(Posted 2013) [#40]
@DruggedBunny: I have an old project with those 2 functions... The filename is AutoFit. I never used Nobuyuki's AutoScale :D


Function GetBlackWidth:Int()
	Return VirtualDisplay.Display.widthborder
End

Function GetMultiratio:Float()
	Return VirtualDisplay.Display.multi
End


Strange...


DruggedBunny(Posted 2013) [#41]
Someone else must have added those, then -- didn't have a GetBlackWidth either!


Arabia(Posted 2013) [#42]
Finally got around to downloading this and giving it a go. Took me all of 5 mins to update my code and get it working.

Thanks DruggedBunny, saved me a lot of work and most likely headaches trying to do this myself.


rIKmAN(Posted 2013) [#43]
I've got a bit of a weird one and was wondering if I could get some help?

I've been using autofit 2.0 in my project for a while now without issues - so much so that I had forgotten about it - and everything has been working great, but it's started playing silly buggers tonight and I have no idea why.

It is 'Imported' fine, and the SetVirtualDisplay and UpdateVirtualDisplay are tokenised normally in the editor (JungleIDE) so the keywords are recognised properly, everything compiles etc

However if I add VMouseX(), VMouseY(), VTouchX() or VTouchY() then I've noticed that they are tokenised in italic, and I get the following error when I actually click/touch:
Monkey Runtime Error : TypeError: Cannot call method 'p_TouchX' of null

The code I am running to get this is just a debug line:
If TouchHit(0)
    DebugLog "vx: " + VTouchX() + " , vy: " + VTouchY()
EndIf

I should note that I am also using iEngine from the Ignition Framework to swap between game states, and that autofit is working fine in one of the other states (and the commands are not italic in that source either) - just not in this particular one that I added tonight.

I have tried adding autofit, SetVirtualDisplay and UpdateVirtualDisplay to the files manually (as opposed to Importing them from another file) but the issue persists and I keep getting the null error.

Anyone got any ideas?


rIKmAN(Posted 2013) [#44]
OK I seem to have found the problem - I now have precede the VTouchX/VTouchY() etc commands like so...

 DrawText "I'm scaled", autofit.VTouchX(), autofit.VTouchY()

I guess something changed since I first used the autofit stuff I coded, but I'll leave it here in case anyone else has the same issue in future.


DruggedBunny(Posted 2013) [#45]
Hmm, I can only imagine another module has similarly-named commands if that's what solved it.