window aspect ratio handler

If you change the window size pictures and gui elements will not be scaled to match the size of the window automatically (if the aspect ratio changes, size will be changed).

This small script will change a image (like a startscreen, gui element etc.) to scale accordingly to the window aspect ratio.

import direct.directbase.DirectStart
from direct.gui.OnscreenImage import OnscreenImage
from direct.showbase.DirectObject import DirectObject

class aspectRatioScaler( DirectObject ):
  def __init__( self ):
    self.startImage = OnscreenImage(image = 'image.jpg')
    self.windowEventSetup()

  def windowEventSetup( self ):
    # accept the window event's
    self.accept( 'window-event', self.windowEventHandler)
    # create a window event yourself
    messenger.send( 'window-event', [base.win] )
  
  def windowEventHandler( self, window=None ):
    """
    This is a special callback.
    It is called when the panda window is modified.
    """
    if window is not None: # window is none if panda3d is not started
      wp = window.getProperties()
      wpXSize = wp.getXSize()
      wpYSize = wp.getYSize()
      if wpXSize > wpYSize:
        height = 1.0
        width = wpXSize / float(wpYSize)
      else:
        height = wpYSize / float(wpXSize)
        width = 1.0
      self.startImage.setScale( width, 1, height )

if __name__ == '__main__':
  a = aspectRatioScaler()
  run()

Another approach, for static images at least, is simply to parent it to render2d instead of aspect2d, since render2d always matches the window exactly. It is just the scale of aspect2d that is adjusted when the window’s aspect ratio changes (which makes sense, since the purpose of aspect2d is to compensate for the window’s aspect ratio).

You can’t parent interactive DirectGui elements to render2d, however. DirectGui elements must always be parented somewhere beneath aspect2d in order for them to function properly.

David

DGUI can be parented to render2d, I just have to replace the real render2d with PGTop :

      newR2d=PGTop('render2d')
      newR2d.stealChildren(render2d.node())
      newR2d.setState(render2d.getState())
      newR2d.setMouseWatcher(base.buttonThrowers[0].getParent().node())
      __builtins__.render2d=render2d.attachNewNode(newR2d)
      base.cam2d.node().setScene(render2d)

Thanks a lot!
Prety code.