• Dear Cerberus X User!

    As we prepare to transition the forum ownership from Mike to Phil (TripleHead GmbH), we need your explicit consent to transfer your user data in accordance with our amended Terms and Rules in order to be compliant with data protection laws.

    Important: If you accept the amended Terms and Rules, you agree to the transfer of your user data to the future forum owner!

    Please read the new Terms and Rules below, check the box to agree, and click "Accept" to continue enjoying your Cerberus X Forum experience. The deadline for consent is April 5, 2024.

    Do not accept the amended Terms and Rules if you do not wish your personal data to be transferred to the future forum owner!

    Accepting ensures:

    - Continued access to your account with a short break for the actual transfer.

    - Retention of your data under the same terms.

    Without consent:

    - You don't have further access to your forum user account.

    - Your account and personal data will be deleted after April 5, 2024.

    - Public posts remain, but usernames indicating real identity will be anonymized. If you disagree with a fictitious name you have the option to contact us so we can find a name that is acceptable to you.

    We hope to keep you in our community and see you on the forum soon!

    All the best

    Your Cerberus X Team

Snippet Re-virtual resolution

Wingnut

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,414
I've been looking a long time for a efficient and easy way to create a virtual resolution on all devices including mobiles and desktops.

There's autofit, it's for mojo1 only but I was thinking of converting it only to discover it might not be a good idea, also it's blurry (which could be a postive thing sometimes but it was too blurry for my taste).

Next up was letterbox for mojo2, I don't know why but it just wasn't reliable on my Mac and phone, strangely offset and getting stuck in all kinds of resolutions. It might be me. But I tried for a some weeks.

The last resort would be to go for a framework, there are a few. This is not something I ever do so what I would do would be to dive into the frameworks just to see how they did it. I didn't have the energy to do that.

So I made this. Maybe someone else likes it too so let me share it.

What it does :
You tell what resolution you have and what you would like to have instead and it will
find the biggest integer scale that you can fit and centre it nicely on the screen, and it does this with an optional background!

EDIT if you wonder weather it's pixel-perfect if you happen to use your exact native screen as your virtual screen,
the answer is actually yes. It does not make a single misstake, so it's a nice base to have.

Cerberus:
Import mojo2

Function Main ()
    New Game
End

Class Game Extends App

    Field screen2:Image
    Field screen2canvas:Canvas
    Field intwidth:Int, intheight:Int
    Field startx:Int, starty:Int
    Field canvas:Canvas
    Field size:Int=8
    Field cx:Int
    Field wx:Int
    Field wy:Int
    Field tilemap:Int[512*512]
    Field s:Int = 2
    Field background:Image

    ' --------------------------------
    ' Virtual resolution
    Field vwidth:Int = 320 ' 200'320
    Field vheight:Int = 200 ' 320'200

    ' Native resolution or windowsize
    Field awidth:Int = 1440 ' 720'1440
    Field aheight:Int = 900 ' 1280'900
    ' ---------------------------------

    Method OnCreate ()
        For Local y:=0 To 511
            For Local x:=0 To 511
                tilemap[x + y * 512] = Int(Rnd(127))
            Next
        Next
        background=Image.Load("80s.png",0,0,0)
        Image.SetFlagsMask(Image.Managed)
        SetDeviceWindow awidth,aheight,1 ' 4
        canvas=New Canvas
        screen2=New Image(vwidth,vheight,0,0,0)
        screen2.SetFlagsMask(screen2.Managed)
        screen2canvas=New Canvas(screen2)
        SetSwapInterval 1
        SetUpdateRate 0
        HideMouse
        Return 0
    End

    Method OnUpdate ()
        If KeyHit(KEY_ESCAPE) Then EndApp
        wx=wx-s*KeyDown(KEY_LEFT)+s*KeyDown(KEY_RIGHT)
        wy=wy-s*KeyDown(KEY_UP)+s*KeyDown(KEY_DOWN)
        wx=Max(0,Min(10000,wx))
        wy=Max(0,Min(10000,wy))
    End

    Method OnRender ()
        canvas.Clear 0,0,0
        ' Calculate how to put the biggest integer version of our wanted virtual resolution on the screen
        intwidth = Floor(Float(awidth)/Float(vwidth))
         intheight = Floor(Float(aheight)/Float(vheight))
         If intwidth > intheight Then intwidth = intheight
         If intheight > intwidth Then intheight = intwidth
         startx = (awidth-(vwidth*intwidth)) / 2
         starty = (aheight-(vheight*intheight)) / 2

         ' Done thinking, let's make it happen! Let's draw on our virtual screen, below follows an example
        screen2canvas.Clear 0,0,0
        screen2canvas.SetColor 1,1,1
        Local w=320
        Local h=200
        wx=wx+1 Mod 4096
        Local scrx:=wx Mod size
        Local scry:=wy Mod size
        Local mapx:=wx / size
        Local mapy:=wy / size
        Local cnty:= -scry
        For Local y:=mapy To mapy+((h/size)+1)
            Local cntx:=-scrx
            For Local x:=mapx To mapx+((w/size)+1)
                screen2canvas.DrawOval cntx,cnty,size,size
                cntx=cntx+size
            Next
            cnty=cnty+size
        Next
        screen2canvas.Flush

        ' Now draw everything onto the native canvas
        canvas.SetColor 1,1,1
        canvas.DrawRect 0,0,awidth,aheight,background,0,0,890,1213 ' hardcoded width and height of example image
        canvas.DrawImage screen2,startx,starty,0,intwidth,intheight
        canvas.Flush
    End
End
 

Attachments

  • screenshot.png
    screenshot.png
    316.7 KB · Views: 155
  • 80s.png
    80s.png
    1.7 MB · Views: 1,884
Last edited:
By the way if you don't care about integer scaling and what you want is to have everything as big
as possible on any screen while keeping the ratio intact, just change the two "FLOOR" into "FLOAT" and you are perfect to go. You can achieve this by just deleting the two FLOOR's actually.
 
As a bonus version which gives you information how much room you've got in the border if any.

With this you can decide if you want to use the space for e.g. showing information such as score or whatever in the border instead of overlaying the gameplay area. It gives you this information in the form of pixels and percentages of the screen area.

Just make sure that you set your wanted virtual resolution, your Native resolution and finally the mode which is 1 for fullscreen or 4 for windowed.

EDIT Windowed mode is great for testing, and as an exercise you can try changing the virtual resolution and maybe set it to the same as the native resolution and sSee how different combinations react.


Cerberus:
Import mojo2

Function Main ()
    New Game
End

Class Game Extends App
  
    Field screen2:Image
    Field screen2canvas:Canvas
    Field intwidth:Float, intheight:Float ' Float or Int, both works
    Field startx:Int, starty:Int
    Field canvas:Canvas
    Field size:Int=8
    Field cx:Int
    Field wx:Int
    Field wy:Int
    Field tilemap:Int[512*512]
    Field s:Int = 2
    Field background:Image
  
    ' --------------------------------
    ' Virtual res§olution
    Field vwidth:Int= 320' 200'320
    Field vheight:Int = 200 ' 320'200
  
    ' Native resolution or windowsize
    Field awidth:Int = 1440/4 ' 720'1440 < put anything you want here
    Field aheight:Int = 900/4 ' 1280'900 <
    ' ---------------------------------
  
    Method OnCreate ()
        For Local y:=0 To 511
            For Local x:=0 To 511
                tilemap[x + y * 512] = Int(Rnd(127))
            Next
        Next
        background=Image.Load("80s.png",0,0,0)
        Image.SetFlagsMask(Image.Managed)
        SetDeviceWindow awidth,aheight,4 '  < Put 4 here for Windowed and 1 for Fullscreen
        canvas=New Canvas
        screen2=New Image(vwidth,vheight,0,0,0)
        screen2.SetFlagsMask(screen2.Managed)
        screen2canvas=New Canvas(screen2)
        SetSwapInterval 1
        SetUpdateRate 0
        HideMouse
        Return 0
    End

    Method OnUpdate ()      
        If KeyHit(KEY_ESCAPE) Then EndApp      
        wx=wx-s*KeyDown(KEY_LEFT)+s*KeyDown(KEY_RIGHT)
        wy=wy-s*KeyDown(KEY_UP)+s*KeyDown(KEY_DOWN)
        wx=Max(0,Min(10000,wx))
        wy=Max(0,Min(10000,wy))
    End

    Method OnRender ()
        canvas.Clear 0,0,0
        ' Calculate how to put the biggest integer version of our wanted virtual resolution on the screen
        intwidth = Floor(Float(awidth)/Float(vwidth))
         intheight = Floor(Float(aheight)/Float(vheight))
       
         ' Uncomment if you don't care about integer scaling, you just want to fit everything as big as possible perfectly and keep the ratio
         ' intwidth = (Float(awidth)/Float(vwidth)) ' Lots of floats statements here, they're actually not all needed
         ' intheight = (Float(aheight)/Float(vheight))
       
         If intwidth > intheight Then intwidth = intheight
         If intheight > intwidth Then intheight = intwidth
         startx = (awidth-(vwidth*intwidth)) / 2
         starty = (aheight-(vheight*intheight)) / 2
       
         ' -------------------------------------------------------------------
         ' CALCULATE BORDERSIZE SO WE CAN CHOOSE TO WRITE SCORE AND LIVES NEATLY
         ' IF THERE'S ENOUGH SPACE ON A PARTICULAR SCREEN

        ' GET SIZE IN PIXELS :
         ' STARTX = HORISONTAL BORDERSIZE IN PIXEL, we already calculated above
         ' STARTY = VERTICAL BORDERSIZE IN PIXELS, we already calculated above
       
         ' GET SIZE IN PERCENTAGE :
            Local borderwidthpercetage:Float = Float(startx)/Float(awidth)
            Local borderheightpercentage:Float = Float(starty)/Float(aheight)
         ' -------------------------------------------------------------------
       
         ' Adding calcluating sides and also dynamic superpositioned left rght up down big area
       
         ' Done thinking, let's make it happen! Let's draw on our virtual screen
        screen2canvas.Clear 0,0,0
        screen2canvas.SetColor 1,1,1
        Local w=320
        Local h=200
        wx=wx+1 Mod 4096
        Local scrx:=wx Mod size
        Local scry:=wy Mod size
        Local mapx:=wx / size
        Local mapy:=wy / size  
        Local cnty:= -scry
        For Local y:=mapy To mapy+((h/size)+1)
            Local cntx:=-scrx
            For Local x:=mapx To mapx+((w/size)+1)
                screen2canvas.DrawOval cntx,cnty,size,size
                cntx=cntx+size
            Next
            cnty=cnty+size
        Next
        screen2canvas.Flush

        ' Now draw everything onto then native canvas
        canvas.SetColor 1,1,1
        canvas.DrawRect 0,0,awidth,aheight,background,0,0,890,1213 ' hardcoded width and height of example image
        canvas.DrawImage screen2,startx,starty,0,intwidth,intheight
  
        ' ---------------------------------------------------------------------------------------------------
        '
        ' If we have at least e.g. 1% of the screen height (or 20 pixels) to spare in the
        ' border then write score in the border instead of on top of the game screen
        '
        If borderheightpercentage > 0.01 ' If we want to check percentage of space the border takes of the screen
        ' If starty > 20                  ' If we want to check the number of pixels instead to get the feeling of how much room we've got to spare
            canvas.DrawText("SCORE GOES HERE", awidth / 2.0, (starty-10) / 2, .5)                   ' top border
            canvas.DrawText("SCORE GOES HERE", awidth / 2.0, aheight - ((starty+10) / 2), .5) ' bottom border
        Endif
        '
        ' ---------------------------------------------------------------------------------------------------
                  
        canvas.Flush
    End

    Method OnLoading:Int()
        Return 0
    End
  
    Method OnResume:Int()
        Return 0
    End
  
    Method OnSuspend:Int()
        Return 0
    End

End
 
Last edited:
Back
Top Bottom