Skip to content

Commit 2948d4b

Browse files
committed
Extract non PoD arguments from the Camera2D init and add a RenderTarget property to Camera2D
The render target change was discussed with @einarf. May extend to other camera types later.
1 parent fa97758 commit 2948d4b

File tree

1 file changed

+69
-47
lines changed

1 file changed

+69
-47
lines changed

arcade/camera/camera_2d.py

Lines changed: 69 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from arcade.camera.orthographic import OrthographicProjector
66
from arcade.camera.data_types import CameraData, OrthographicProjectionData, Projector
7+
from arcade.gl import Framebuffer
78

89
from arcade.window_commands import get_window
910
if TYPE_CHECKING:
@@ -43,71 +44,88 @@ class Camera2D:
4344
4445
:param window: The Arcade Window to bind the camera to.
4546
Defaults to the currently active window.
46-
:param viewport: A 4-int tuple which defines the pixel bounds which the camera with project to.
47-
:param position: The 2D position of the camera in the XY plane.
48-
:param up: The 2D unit vector which defines the +Y-axis of the camera space.
49-
:param zoom: A scalar value which is inversely proportional to the size of the camera projection.
50-
i.e. a zoom of 2.0 halves the size of the projection, doubling the perceived size of objects.
51-
:param projection: A 4-float tuple which defines the world space
52-
bounds which the camera projects to the viewport.
53-
:param near: The near clipping plane of the camera.
54-
:param far: The far clipping plane of the camera.
5547
:param camera_data: A :py:class:`~arcade.camera.data.CameraData`
5648
describing the viewport, position, up, and zoom.
5749
:param projection_data: A :py:class:`~arcade.camera.data.OrthographicProjectionData`
5850
which describes the left, right, top, bottom, far, near planes for an orthographic projection.
51+
:param render_target: The FrameBuffer that the camera uses. Defaults to the screen.
52+
If the framebuffer is not the default screen nothing drawn after this camera is used will
53+
show up. The FrameBuffer's internal viewport is ignored.
5954
"""
6055
def __init__(self, *,
61-
window: Optional["Window"] = None,
62-
viewport: Optional[Tuple[int, int, int, int]] = None,
63-
position: Optional[Tuple[float, float]] = None,
64-
up: Optional[Tuple[float, float]] = None,
65-
zoom: Optional[float] = None,
66-
projection: Optional[Tuple[float, float, float, float]] = None,
67-
near: Optional[float] = None,
68-
far: Optional[float] = None,
69-
camera_data: Optional[CameraData] = None,
70-
projection_data: Optional[OrthographicProjectionData] = None
71-
):
72-
window = window or get_window()
73-
self._window: "Window" = window
56+
camera_data: CameraData,
57+
projection_data: OrthographicProjectionData,
58+
render_target: Optional[Framebuffer] = None,
59+
window: Optional["Window"] = None):
60+
self._window: "Window" = window or get_window()
61+
self.render_target: Framebuffer = render_target or self._window.ctx.screen
7462

75-
assert (
76-
not any((viewport, position, up, zoom)) or not camera_data
77-
), (
78-
"Camera2D Warning: Provided both a CameraData object and raw values. Defaulting to CameraData."
79-
)
63+
self._data = camera_data
64+
self._projection: OrthographicProjectionData = projection_data
8065

81-
assert (
82-
not any((projection, near, far)) or not projection_data
83-
), (
84-
"Camera2D Warning: Provided both an OrthographicProjectionData object and raw values."
85-
"Defaulting to OrthographicProjectionData."
66+
self._ortho_projector: OrthographicProjector = OrthographicProjector(
67+
window=self._window,
68+
view=self._data,
69+
projection=self._projection
8670
)
8771

88-
half_width = window.width/2
89-
half_height = window.height/2
72+
@staticmethod
73+
def from_raw_data(
74+
viewport: Optional[Tuple[int, int, int, int]] = None,
75+
position: Optional[Tuple[float, float]] = None,
76+
up: Tuple[float, float] = (0.0, 1.0),
77+
zoom: float = 1.0,
78+
projection: Optional[Tuple[float, float, float, float]] = None,
79+
near: float = -100,
80+
far: float = 100,
81+
*,
82+
render_target: Optional[Framebuffer] = None,
83+
window: Optional["Window"] = None
84+
):
85+
"""
86+
Create a Camera2D without first defining CameraData or an OrthographicProjectionData object.
87+
88+
:param viewport: A 4-int tuple which defines the pixel bounds which the camera with project to.
89+
:param position: The 2D position of the camera in the XY plane.
90+
:param up: The 2D unit vector which defines the +Y-axis of the camera space.
91+
:param zoom: A scalar value which is inversely proportional to the size of the camera projection.
92+
i.e. a zoom of 2.0 halves the size of the projection, doubling the perceived size of objects.
93+
:param projection: A 4-float tuple which defines the world space
94+
bounds which the camera projects to the viewport.
95+
:param near: The near clipping plane of the camera.
96+
:param far: The far clipping plane of the camera.
97+
:param render_target: The FrameBuffer that the camera uses. Defaults to the screen.
98+
If the framebuffer is not the default screen nothing drawn after this camera is used will
99+
show up. The FrameBuffer's internal viewport is ignored.
100+
:param window: The Arcade Window to bind the camera to.
101+
Defaults to the currently active window.
102+
"""
103+
window = window or get_window()
104+
105+
half_width = window.width / 2
106+
half_height = window.height / 2
90107

91108
_pos = position or (half_width, half_height)
92-
_up = up or (0.0, 1.0)
93-
self._data = camera_data or CameraData(
94-
(_pos[0], _pos[1], 0.0),
95-
(_up[0], _up[1], 0.0),
96-
(0.0, 0.0, -1.0),
97-
zoom or 1.0
109+
_data: CameraData = CameraData(
110+
(_pos[0], _pos[1], 0.0), # position
111+
(up[0], up[1], 0.0), # up vector
112+
(0.0, 0.0, -1.0), # forward vector
113+
zoom # zoom
98114
)
99115

100-
self._projection: OrthographicProjectionData = projection_data or OrthographicProjectionData(
101-
-half_width, half_width, # Left and Right.
102-
-half_height, half_height, # Bottom and Top.
116+
left, right, bottom, top = projection or (-half_width, half_width, -half_height, half_height)
117+
_projection: OrthographicProjectionData = OrthographicProjectionData(
118+
left, right, # Left and Right.
119+
top, bottom, # Bottom and Top.
103120
near or 0.0, far or 100.0, # Near and Far.
104121
viewport or (0, 0, window.width, window.height) # Viewport
105122
)
106123

107-
self._ortho_projector: OrthographicProjector = OrthographicProjector(
108-
window=self._window,
109-
view=self._data,
110-
projection=self._projection
124+
return Camera2D(
125+
camera_data=_data,
126+
projection_data=_projection,
127+
window=window,
128+
render_target= (render_target or window.ctx.screen)
111129
)
112130

113131
@property
@@ -662,6 +680,7 @@ def use(self) -> None:
662680
663681
If you want to use a 'with' block use activate() instead.
664682
"""
683+
self.render_target.use()
665684
self._ortho_projector.use()
666685

667686
@contextmanager
@@ -675,10 +694,13 @@ def activate(self) -> Iterator[Projector]:
675694
the projector to the one previously in use.
676695
"""
677696
previous_projection = self._window.current_camera
697+
previous_framebuffer = self._window.ctx.active_framebuffer
678698
try:
699+
self.render_target.use()
679700
self.use()
680701
yield self
681702
finally:
703+
previous_framebuffer.use()
682704
previous_projection.use()
683705

684706
def map_coordinate(self, screen_coordinate: Tuple[float, float], depth: float = 0.0) -> Tuple[float, float]:

0 commit comments

Comments
 (0)