77from pyglet .math import Mat4 , Vec2 , Vec3
88from typing_extensions import Self
99
10- from arcade .types import LBWH , Point , Rect
10+ from arcade .camera .data_types import DEFAULT_FAR , DEFAULT_NEAR_ORTHO
11+ from arcade .types import Point
1112from arcade .window_commands import get_window
1213
1314if TYPE_CHECKING :
1415 from arcade .context import ArcadeContext
1516
16- __all__ = [ "ViewportProjector" , "DefaultProjector" ]
17+ __all__ = ()
1718
1819
19- class ViewportProjector :
20+ class DefaultProjector :
2021 """
21- A simple Projector which does not rely on any camera PoDs.
22+ An extremely limited projector which lacks any kind of control. This is only
23+ here to act as the default camera used internally by Arcade. There should be
24+ no instance where a developer would want to use this class.
2225
23- Does not have a way of moving, rotating, or zooming the camera.
24- perfect for something like UI or for mapping to an offscreen framebuffer.
26+ The job of the default projector is to ensure that when no other Projector
27+ (Camera2D, OthrographicProjector, PerspectiveProjector, etc) is in use the
28+ projection and view matrices are correct such at (0.0, 0.0) is in the bottom
29+ left corner of the viewport and that one pixel equals one 'unit'.
2530
2631 Args:
27- viewport: The viewport to project to.
28- context: The window context to bind the camera to. Defaults to the currently active window.
32+ context: The window context to bind the camera to. Defaults to the currently active context.
2933 """
3034
31- def __init__ (
32- self ,
33- viewport : Rect | None = None ,
34- * ,
35- context : ArcadeContext | None = None ,
36- ):
35+ def __init__ (self , * , context : ArcadeContext | None = None ):
3736 self ._ctx : ArcadeContext = context or get_window ().ctx
38- self ._viewport : Rect = viewport or LBWH (* self ._ctx .viewport )
39- self ._projection_matrix : Mat4 = Mat4 .orthogonal_projection (
40- 0.0 , self ._viewport .width , 0.0 , self ._viewport .height , - 100 , 100
41- )
37+ self ._viewport : tuple [int , int , int , int ] | None = None
38+ self ._scissor : tuple [int , int , int , int ] | None = None
39+ self ._matrix : Mat4 | None = None
4240
43- @property
44- def viewport (self ) -> Rect :
41+ def update_viewport (self ):
4542 """
46- The viewport use to derive projection and view matrix.
43+ Called when the ArcadeContext's viewport or active
44+ framebuffer has been set. It only actually updates
45+ the viewport if no other camera is active. Also
46+ setting the viewport to match the size of the active
47+ framebuffer sets the viewport to None.
4748 """
49+
50+ # If another camera is active then the viewport was probably set
51+ # by camera.use()
52+ if self ._ctx .current_camera != self :
53+ return
54+
55+ if (
56+ self ._ctx .viewport [2 ] != self ._ctx .fbo .width
57+ or self ._ctx .viewport [3 ] != self ._ctx .fbo .height
58+ ):
59+ self .viewport = self ._ctx .viewport
60+ else :
61+ self .viewport = None
62+
63+ self .use ()
64+
65+ @property
66+ def viewport (self ) -> tuple [int , int , int , int ] | None :
4867 return self ._viewport
4968
5069 @viewport .setter
51- def viewport (self , viewport : Rect ) -> None :
70+ def viewport (self , viewport : tuple [int , int , int , int ] | None ) -> None :
71+ if viewport == self ._viewport :
72+ return
5273 self ._viewport = viewport
53- self ._projection_matrix = Mat4 .orthogonal_projection (
54- 0 , viewport .width , 0 , viewport .height , - 100 , 100
74+ self ._matrix = Mat4 .orthogonal_projection (
75+ 0 , self .width , 0 , self .height , DEFAULT_NEAR_ORTHO , DEFAULT_FAR
5576 )
5677
78+ @viewport .deleter
79+ def viewport (self ):
80+ self .viewport = None
81+
82+ @property
83+ def scissor (self ) -> tuple [int , int , int , int ] | None :
84+ return self ._scissor
85+
86+ @scissor .setter
87+ def scissor (self , scissor : tuple [int , int , int , int ] | None ) -> None :
88+ self ._scissor = scissor
89+
90+ @scissor .deleter
91+ def scissor (self ) -> None :
92+ self ._scissor = None
93+
94+ @property
95+ def width (self ) -> int :
96+ if self ._viewport is not None :
97+ return int (self ._viewport [2 ])
98+ return self ._ctx .fbo .width
99+
100+ @property
101+ def height (self ) -> int :
102+ if self ._viewport is not None :
103+ return int (self ._viewport [3 ])
104+ return self ._ctx .fbo .height
105+
106+ def get_current_viewport (self ) -> tuple [int , int , int , int ]:
107+ if self ._viewport is not None :
108+ return self ._viewport
109+ return (0 , 0 , self ._ctx .fbo .width , self ._ctx .fbo .height )
110+
57111 def use (self ) -> None :
58112 """
59- Set the window's projection and view matrix.
60- Also sets the projector as the windows current camera.
113+ Set the window's Projection and View matrices.
61114 """
62- self ._ctx .current_camera = self
63115
64- self ._ctx .viewport = self .viewport .lbwh_int # get the integer 4-tuple LBWH
116+ viewport = self .get_current_viewport ()
117+
118+ self ._ctx .current_camera = self
119+ if self ._ctx .viewport != viewport :
120+ self ._ctx .active_framebuffer .viewport = viewport
121+ self ._ctx .scissor = None if self ._scissor is None else self ._scissor
65122
66123 self ._ctx .view_matrix = Mat4 ()
67- self ._ctx .projection_matrix = self ._projection_matrix
124+ if self ._matrix is None :
125+ self ._matrix = Mat4 .orthogonal_projection (
126+ 0 , viewport [2 ], 0 , viewport [3 ], DEFAULT_NEAR_ORTHO , DEFAULT_FAR
127+ )
128+ self ._ctx .projection_matrix = self ._matrix
68129
69130 @contextmanager
70131 def activate (self ) -> Generator [Self , None , None ]:
@@ -73,12 +134,20 @@ def activate(self) -> Generator[Self, None, None]:
73134
74135 usable with the 'with' block. e.g. 'with ViewportProjector.activate() as cam: ...'
75136 """
76- previous = self ._ctx .current_camera
137+ previous_projector = self ._ctx .current_camera
138+ previous_view = self ._ctx .view_matrix
139+ previous_projection = self ._ctx .projection_matrix
140+ previous_scissor = self ._ctx .scissor
141+ previous_viewport = self ._ctx .viewport
77142 try :
78143 self .use ()
79144 yield self
80145 finally :
81- previous .use ()
146+ self ._ctx .viewport = previous_viewport
147+ self ._ctx .scissor = previous_scissor
148+ self ._ctx .projection_matrix = previous_projection
149+ self ._ctx .view_matrix = previous_view
150+ self ._ctx .current_camera = previous_projector
82151
83152 def project (self , world_coordinate : Point ) -> Vec2 :
84153 """
@@ -97,46 +166,3 @@ def unproject(self, screen_coordinate: Point) -> Vec3:
97166 z = 0.0 if not _z else _z [0 ]
98167
99168 return Vec3 (x , y , z )
100-
101-
102- # As this class is only supposed to be used internally
103- # I wanted to place an _ in front, but the linting complains
104- # about it being a protected class.
105- class DefaultProjector (ViewportProjector ):
106- """
107- An extremely limited projector which lacks any kind of control. This is only
108- here to act as the default camera used internally by Arcade. There should be
109- no instance where a developer would want to use this class.
110-
111- Args:
112- context: The window context to bind the camera to. Defaults to the currently active window.
113- """
114-
115- def __init__ (self , * , context : ArcadeContext | None = None ):
116- super ().__init__ (context = context )
117-
118- def use (self ) -> None :
119- """
120- Set the window's Projection and View matrices.
121-
122- cache's the window viewport to determine the projection matrix.
123- """
124-
125- viewport = self .viewport .lbwh_int
126- # If the viewport is correct and the default camera is in use,
127- # then don't waste time resetting the view and projection matrices
128- if self ._ctx .viewport == viewport and self ._ctx .current_camera == self :
129- return
130-
131- # If the viewport has changed while the default camera is active then the
132- # default needs to update itself.
133- # If it was another camera's viewport being used the default camera should not update.
134- if self ._ctx .viewport != viewport and self ._ctx .current_camera == self :
135- self .viewport = LBWH (* self ._ctx .viewport )
136- else :
137- self ._ctx .viewport = viewport
138-
139- self ._ctx .current_camera = self
140-
141- self ._ctx .view_matrix = Mat4 ()
142- self ._ctx .projection_matrix = self ._projection_matrix
0 commit comments