Skip to content

updated ViewportProjector to use Rect, and created unit tests #2343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading