Skip to content

Instantly share code, notes, and snippets.

@CowThing
Last active August 24, 2025 04:53
Show Gist options
  • Select an option

  • Save CowThing/2f091036457da281c546937bc8fad695 to your computer and use it in GitHub Desktop.

Select an option

Save CowThing/2f091036457da281c546937bc8fad695 to your computer and use it in GitHub Desktop.

Revisions

  1. CowThing revised this gist Mar 6, 2019. 1 changed file with 19 additions and 9 deletions.
    28 changes: 19 additions & 9 deletions pixel_perfect.gd
    Original file line number Diff line number Diff line change
    @@ -4,13 +4,15 @@ extends Node
    An autoload singleton for pixel perfect rendering of the game.
    Set this script as an autoload.
    `base_size` is the target size of the viewport. The viewport will scale up to fit the largest
    `base_size` - Is the target size of the viewport. The viewport will scale up to fit the largest
    possible integer multiple of this size within the window.
    `expand` if true the viewport will expand to the edges of the window after scaling up.
    `expand` - If true the viewport will expand to the edges of the window after scaling up.
    Otherwise the empty space outside of the viewport will be filled with black bars.
    `pixel_perfect` - if false the viewport will still scale up, but not render pixel perfectly.
    `pixel_perfect` - If false the viewport will still scale up, but not render pixel perfectly.
    `pixel_aspect` - Used to stretch pixels to a non-square size.
    Notes
    ----
    @@ -25,6 +27,7 @@ onready var _root : Viewport = get_tree().root
    var base_size : = Vector2(640, 360) setget set_base_size
    var expand : = false setget set_expand
    var pixel_perfect : = true setget set_pixel_perfect
    var pixel_aspect : = Vector2(1, 1) setget set_pixel_aspect


    func _ready() -> void:
    @@ -51,29 +54,36 @@ func set_pixel_perfect(value : bool) -> void:
    _on_screen_resized()


    func set_pixel_aspect(value : Vector2) -> void:
    pixel_aspect = value
    _on_screen_resized()


    func _on_screen_resized() -> void:
    var new_window_size : = OS.window_size

    var scale_width : = max(1, new_window_size.x / base_size.x)
    var scale_height : = max(1, new_window_size.y / base_size.y)
    var total_base_size : Vector2 = base_size * pixel_aspect

    var scale_width : = max(1, new_window_size.x / total_base_size.x)
    var scale_height : = max(1, new_window_size.y / total_base_size.y)
    var scale : = min(scale_width, scale_height) as int

    var size : Vector2 = new_window_size / scale if expand else base_size
    var size : Vector2 = new_window_size / scale if expand else total_base_size
    size = size.floor()

    var offset : Vector2 = (new_window_size - size * scale) * 0.5
    offset = offset.floor()

    if pixel_perfect:
    _root.size = size
    _root.size = size / pixel_aspect
    _root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    _root.set_size_override(false)
    _root.set_size_override_stretch(false)

    else:
    _root.size = size * scale
    _root.size = (size * scale) / pixel_aspect
    _root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    _root.set_size_override(true, size)
    _root.set_size_override(true, size / pixel_aspect)
    _root.set_size_override_stretch(true)

    offset.x = max(0, offset.x)
  2. CowThing revised this gist Jan 27, 2019. 1 changed file with 45 additions and 40 deletions.
    85 changes: 45 additions & 40 deletions pixel_perfect.gd
    Original file line number Diff line number Diff line change
    @@ -1,82 +1,87 @@
    extends Node

    # Set this script as an Autoload singleton
    """
    An autoload singleton for pixel perfect rendering of the game.
    Set this script as an autoload.
    # Optional black bar texture, use a single colored square to make the black bars a different color.
    const black_bar_texture = preload("res://black_bars.png")
    `base_size` is the target size of the viewport. The viewport will scale up to fit the largest
    possible integer multiple of this size within the window.
    # The target size for the viewport.
    var base_size = Vector2(480, 270) setget set_base_size
    `expand` if true the viewport will expand to the edges of the window after scaling up.
    Otherwise the empty space outside of the viewport will be filled with black bars.
    # If true the viewport will expand to fill any extra space in the window.
    var expand = false setget set_expand
    `pixel_perfect` - if false the viewport will still scale up, but not render pixel perfectly.
    # If true the viewport will render at the base_size.
    var pixel_perfect = true setget set_pixel_perfect
    Notes
    ----
    The commented out code for black bar texture will let you set the texture of the black bars.
    This is a work around until black bars can be easily edited in a project.
    """

    onready var root = get_tree().root
    onready var _root : Viewport = get_tree().root

    # const black_bar_texture = preload("res://black_bars.png")

    func _ready():
    var base_size : = Vector2(640, 360) setget set_base_size
    var expand : = false setget set_expand
    var pixel_perfect : = true setget set_pixel_perfect


    func _ready() -> void:
    get_tree().connect("screen_resized", self, "_on_screen_resized")

    var t_id = black_bar_texture.get_rid()
    VisualServer.black_bars_set_images(t_id, t_id, t_id, t_id)
    # var t_id = black_bar_texture.get_rid()
    # VisualServer.black_bars_set_images(t_id, t_id, t_id, t_id)

    _on_screen_resized()


    func set_base_size(value):
    func set_base_size(value : Vector2) -> void:
    base_size = value.floor()
    _on_screen_resized()


    func set_expand(value):
    func set_expand(value : bool) -> void:
    expand = value
    _on_screen_resized()


    func set_pixel_perfect(value):
    func set_pixel_perfect(value : bool) -> void:
    pixel_perfect = value
    _on_screen_resized()


    func _on_screen_resized():
    var new_window_size = OS.window_size
    func _on_screen_resized() -> void:
    var new_window_size : = OS.window_size

    # Get the minimum scale that fits within the window.
    var scale_width = max(1, new_window_size.x / base_size.x)
    var scale_height = max(1, new_window_size.y / base_size.y)
    var scale = int(min(scale_width, scale_height))
    var scale_width : = max(1, new_window_size.x / base_size.x)
    var scale_height : = max(1, new_window_size.y / base_size.y)
    var scale : = min(scale_width, scale_height) as int

    # Set the size of the desired viewport.
    var size = new_window_size / scale if expand else base_size
    var size : Vector2 = new_window_size / scale if expand else base_size
    size = size.floor()

    # Offset to center the viewport in the window.
    var offset = (new_window_size - size * scale) * 0.5
    var offset : Vector2 = (new_window_size - size * scale) * 0.5
    offset = offset.floor()

    # Set the root size and scale.
    if pixel_perfect:
    root.size = size
    root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    root.set_size_override(false)
    root.set_size_override_stretch(false)
    _root.size = size
    _root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    _root.set_size_override(false)
    _root.set_size_override_stretch(false)

    else:
    root.size = size * scale
    root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    root.set_size_override(true, size)
    root.set_size_override_stretch(true)
    _root.size = size * scale
    _root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    _root.set_size_override(true, size)
    _root.set_size_override_stretch(true)

    # Set black bars to fill in the empty space.
    offset.x = max(0, offset.x)
    offset.y = max(0, offset.y)

    VisualServer.black_bars_set_margins(
    offset.x,
    offset.y,
    new_window_size.x - (offset.x + size.x * scale),
    new_window_size.y - (offset.y + size.y * scale)
    offset.x as int,
    offset.y as int,
    new_window_size.x as int - (offset.x + size.x * scale) as int,
    new_window_size.y as int - (offset.y + size.y * scale) as int
    )
  3. CowThing created this gist Nov 12, 2018.
    82 changes: 82 additions & 0 deletions pixel_perfect.gd
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    extends Node

    # Set this script as an Autoload singleton

    # Optional black bar texture, use a single colored square to make the black bars a different color.
    const black_bar_texture = preload("res://black_bars.png")

    # The target size for the viewport.
    var base_size = Vector2(480, 270) setget set_base_size

    # If true the viewport will expand to fill any extra space in the window.
    var expand = false setget set_expand

    # If true the viewport will render at the base_size.
    var pixel_perfect = true setget set_pixel_perfect

    onready var root = get_tree().root


    func _ready():
    get_tree().connect("screen_resized", self, "_on_screen_resized")

    var t_id = black_bar_texture.get_rid()
    VisualServer.black_bars_set_images(t_id, t_id, t_id, t_id)

    _on_screen_resized()


    func set_base_size(value):
    base_size = value.floor()
    _on_screen_resized()


    func set_expand(value):
    expand = value
    _on_screen_resized()


    func set_pixel_perfect(value):
    pixel_perfect = value
    _on_screen_resized()


    func _on_screen_resized():
    var new_window_size = OS.window_size

    # Get the minimum scale that fits within the window.
    var scale_width = max(1, new_window_size.x / base_size.x)
    var scale_height = max(1, new_window_size.y / base_size.y)
    var scale = int(min(scale_width, scale_height))

    # Set the size of the desired viewport.
    var size = new_window_size / scale if expand else base_size
    size = size.floor()

    # Offset to center the viewport in the window.
    var offset = (new_window_size - size * scale) * 0.5
    offset = offset.floor()

    # Set the root size and scale.
    if pixel_perfect:
    root.size = size
    root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    root.set_size_override(false)
    root.set_size_override_stretch(false)

    else:
    root.size = size * scale
    root.set_attach_to_screen_rect(Rect2(offset, size * scale))
    root.set_size_override(true, size)
    root.set_size_override_stretch(true)

    # Set black bars to fill in the empty space.
    offset.x = max(0, offset.x)
    offset.y = max(0, offset.y)

    VisualServer.black_bars_set_margins(
    offset.x,
    offset.y,
    new_window_size.x - (offset.x + size.x * scale),
    new_window_size.y - (offset.y + size.y * scale)
    )