Skip to content

Commit

Permalink
updated ViewportProjector to use Rect, and created unit tests (#2343)
Browse files Browse the repository at this point in the history
* updated ViewportProjector to use Rect and created unit tests

* linting ✨

* ⬛

* Correcting references to the viewport

Thanks for pointing out the issue, @eruvanos!
  • Loading branch information
DragonMoffon committed Aug 13, 2024
1 parent 83cb72d commit 072101f
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 13 deletions.
27 changes: 14 additions & 13 deletions arcade/camera/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from pyglet.math import Mat4, Vec2, Vec3
from typing_extensions import Self

from arcade.types import Point
from arcade.types import LBWH, Point, Rect
from arcade.window_commands import get_window

if TYPE_CHECKING:
Expand All @@ -29,28 +29,28 @@ class ViewportProjector:

def __init__(
self,
viewport: tuple[int, int, int, int] | None = None,
viewport: Rect | None = None,
*,
context: ArcadeContext | None = None,
):
self._ctx = context or get_window().ctx
self._viewport = viewport or self._ctx.viewport
self._ctx: ArcadeContext = context or get_window().ctx
self._viewport: Rect = viewport or LBWH(*self._ctx.viewport)
self._projection_matrix: Mat4 = Mat4.orthogonal_projection(
0.0, self._viewport[2], 0.0, self._viewport[3], -100, 100
0.0, self._viewport.width, 0.0, self._viewport.height, -100, 100
)

@property
def viewport(self) -> tuple[int, int, int, int]:
def viewport(self) -> Rect:
"""
The viewport use to derive projection and view matrix.
"""
return self._viewport

@viewport.setter
def viewport(self, viewport: tuple[int, int, int, int]) -> None:
def viewport(self, viewport: Rect) -> None:
self._viewport = viewport
self._projection_matrix = Mat4.orthogonal_projection(
0, viewport[2], 0, viewport[3], -100, 100
0, viewport.width, 0, viewport.height, -100, 100
)

def use(self) -> None:
Expand All @@ -60,7 +60,7 @@ def use(self) -> None:
"""
self._ctx.current_camera = self

self._ctx.viewport = self._viewport
self._ctx.viewport = self.viewport.viewport # get the integer 4-tuple LBWH

self._ctx.view_matrix = Mat4()
self._ctx.projection_matrix = self._projection_matrix
Expand Down Expand Up @@ -121,18 +121,19 @@ def use(self) -> None:
cache's the window viewport to determine the projection matrix.
"""

viewport = self.viewport.viewport
# If the viewport is correct and the default camera is in use,
# then don't waste time resetting the view and projection matrices
if self._ctx.viewport == self.viewport and self._ctx.current_camera == self:
if self._ctx.viewport == viewport and self._ctx.current_camera == self:
return

# If the viewport has changed while the default camera is active then the
# default needs to update itself.
# If it was another camera's viewport being used the default camera should not update.
if self._ctx.viewport != self.viewport and self._ctx.current_camera == self:
self.viewport = self._ctx.viewport
if self._ctx.viewport != viewport and self._ctx.current_camera == self:
self.viewport = LBWH(*self._ctx.viewport)
else:
self._ctx.viewport = self.viewport
self._ctx.viewport = viewport

self._ctx.current_camera = self

Expand Down
25 changes: 25 additions & 0 deletions tests/unit/camera/test_viewport_projector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import pytest as pytest

from pyglet.math import Vec3, Vec2

from arcade import camera, Window
from arcade.types import Point, LBWH, Rect

@pytest.mark.parametrize("wrld_pos", [Vec2(100, 150), Vec2(1280, 720), Vec3(500, 500, -10)])
def test_viewport_projector_project(window: Window, wrld_pos: Point):
cam = camera.default.ViewportProjector()
assert cam.project(wrld_pos) == wrld_pos.xy

@pytest.mark.parametrize("wrld_pos", [Vec2(100, 150), Vec2(1280, 720), Vec3(500, 500, -10)])
def test_viewport_projector_unproject(window: Window, wrld_pos: Point):
cam = camera.default.ViewportProjector()
x, y, *z = wrld_pos

assert cam.unproject(wrld_pos) == Vec3(x, y, 0.0 if not z else z[0])

@pytest.mark.parametrize("viewport", [LBWH(0.0, 0.0, 100, 200), LBWH(100, 100, 20, 40), LBWH(300, 20, 20, 700)])
def test_viewport_projector_viewport(window: Window, viewport: Rect):
cam = camera.default.ViewportProjector()
assert cam.viewport.viewport == window.ctx.viewport
cam.viewport = viewport
assert cam.viewport == viewport

0 comments on commit 072101f

Please sign in to comment.