Line data Source code
1 :
2 : /* Copyright (c) 2006-2015, Stefan Eilemann <eile@equalizergraphics.com>
3 : *
4 : * This library is free software; you can redistribute it and/or modify it under
5 : * the terms of the GNU Lesser General Public License version 2.1 as published
6 : * by the Free Software Foundation.
7 : *
8 : * This library is distributed in the hope that it will be useful, but WITHOUT
9 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11 : * details.
12 : *
13 : * You should have received a copy of the GNU Lesser General Public License
14 : * along with this library; if not, write to the Free Software Foundation, Inc.,
15 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 : */
17 :
18 : #ifndef EQFABRIC_PIXELVIEWPORT_H
19 : #define EQFABRIC_PIXELVIEWPORT_H
20 :
21 : #include <eq/fabric/viewport.h> // used in inline method
22 : #include <eq/fabric/pixel.h> // used in inline method
23 : #include <eq/fabric/zoom.h> // used in inline method
24 :
25 : #include <lunchbox/debug.h>
26 :
27 : #include <limits>
28 :
29 : namespace eq
30 : {
31 : namespace fabric
32 : {
33 : /** Holds a 2D pixel viewport with methods for manipulation. */
34 : class PixelViewport
35 : {
36 : public:
37 : /** @name Constructors */
38 : //@{
39 : /** Construct a new, invalid pixel viewport. @version 1.0 */
40 45886 : PixelViewport() : x(0), y(0), w(-1), h(-1) {}
41 :
42 : /** Construct a new pixel viewport with default values. @version 1.0 */
43 575 : PixelViewport( const int32_t x_, const int32_t y_,
44 : const int32_t w_,const int32_t h_ )
45 575 : : x(x_), y(y_), w(w_), h(h_) {}
46 :
47 : /** Construct a new pixel viewport with default values. @version 1.1.6*/
48 0 : explicit PixelViewport( const int32_t pvp[4] )
49 0 : : x( pvp[0] ), y( pvp[1] ), w( pvp[2] ), h( pvp[3] ) {}
50 : //@}
51 :
52 : /** @name Data Access */
53 : //@{
54 : /** Invalidate the pixel viewport. @version 1.0 */
55 1812 : void invalidate() { x = 0; y = 0; w = -1; h = -1; }
56 :
57 : /**
58 : * @return true if the pixel viewport has a non-negative, but
59 : * potentially empty, size.
60 : * @version 1.0
61 : */
62 6090 : bool isValid() const { return (w>=0 && h>=0); }
63 :
64 : /**
65 : * @return true if the pixel viewport has a non-zero area, i.e, it is
66 : * not empty.
67 : * @version 1.0
68 : */
69 4931 : bool hasArea() const { return (w>0 && h>0); }
70 :
71 : /** @return the area in pixels. @version 1.0 */
72 82 : uint32_t getArea() const { return w * h; }
73 :
74 : /**
75 : * @return true if the given point is inside the pixel viewport.
76 : * @version 1.0
77 : */
78 0 : bool isInside( const int32_t pX, const int32_t pY ) const
79 : {
80 0 : if( pX < x || pY < y || pX > (x+w) || pY > (y+h) )
81 0 : return false;
82 0 : return true;
83 : }
84 : //@}
85 :
86 : /** @name Operations */
87 : //@{
88 : /** Apply a fractional viewport to this pixel viewport. @internal */
89 5186 : void apply( const Viewport& rhs )
90 : {
91 : // honor position over size to avoid rounding artifacts
92 5186 : const int32_t xEnd = x + static_cast<int32_t>((rhs.x+rhs.w)*w);
93 5186 : const int32_t yEnd = y + static_cast<int32_t>((rhs.y+rhs.h)*h);
94 :
95 5186 : x += static_cast<int32_t>( w * rhs.x );
96 5186 : y += static_cast<int32_t>( h * rhs.y );
97 5186 : w = xEnd - x;
98 5186 : h = yEnd - y;
99 5186 : }
100 :
101 : /** Apply a pixel decomposition to this pixel viewport. @internal */
102 0 : void apply( const Pixel& pixel )
103 : {
104 0 : if( pixel.w > 1 )
105 : {
106 0 : int32_t newWidth = w / pixel.w;
107 : // This would be the correct thing to do, but it would
108 : // require frustum adaptations in CUV::_computeFrustum:
109 : //if( w - ( newWidth * pixel.w ) > pixel.x )
110 0 : if( w - ( newWidth * pixel.w ) != 0 )
111 0 : ++newWidth;
112 :
113 0 : w = newWidth;
114 : }
115 0 : if( pixel.h > 1 )
116 : {
117 0 : int32_t newHeight = h / pixel.h;
118 : // This would be the correct thing to do, but it would
119 : // require frustum adaptations in CUV::_computeFrustum:
120 : // if( w - ( newWidth * pixel.h ) > pixel.y )
121 0 : if( h - ( newHeight * pixel.h ) != 0 )
122 0 : ++newHeight;
123 :
124 0 : h = newHeight;
125 : }
126 0 : }
127 :
128 : /** Apply a zoom to this pixel viewport. @internal */
129 0 : void apply( const Zoom& zoom )
130 : {
131 0 : if( zoom == Zoom::NONE )
132 0 : return;
133 :
134 0 : x = static_cast< int32_t >( x * zoom.x() + .5f );
135 0 : y = static_cast< int32_t >( y * zoom.y() + .5f );
136 0 : w = static_cast< int32_t >( w * zoom.x() + .5f );
137 0 : h = static_cast< int32_t >( h * zoom.y() + .5f );
138 : }
139 :
140 : /**
141 : * @return the zoom which would result in the given rhs pixel
142 : * viewport when applied to this pixel viewport.
143 : * @internal
144 : */
145 0 : const Zoom getZoom( const PixelViewport& rhs ) const
146 : {
147 0 : if( *this == rhs )
148 0 : return Zoom::NONE;
149 :
150 0 : if( !rhs.hasArea( ))
151 : return Zoom( std::numeric_limits< float >::max(),
152 0 : std::numeric_limits< float >::max( ));
153 :
154 : return Zoom( w / static_cast<float>( rhs.w ),
155 0 : h / static_cast<float>( rhs.h ));
156 : }
157 :
158 : /** @return the X end position. @version 1.0 */
159 0 : int32_t getXEnd() const { return x+w; }
160 :
161 : /** @return the Y end position. @version 1.0 */
162 0 : int32_t getYEnd() const { return y+h; }
163 :
164 : /** Convert into a lunchbox::Plugin usable format. @version 1.5.2 */
165 0 : void convertToPlugin( uint64_t dims[4] ) const
166 : {
167 0 : dims[ 0 ] = x;
168 0 : dims[ 1 ] = w;
169 0 : dims[ 2 ] = y;
170 0 : dims[ 3 ] = h;
171 0 : }
172 :
173 : /** Convert from a lunchbox::Plugin format. @version 1.5.2 */
174 0 : void convertFromPlugin( const uint64_t dims[4] )
175 : {
176 0 : x = int32_t( dims[ 0 ]);
177 0 : w = int32_t( dims[ 1 ]);
178 0 : y = int32_t( dims[ 2 ]);
179 0 : h = int32_t( dims[ 3 ]);
180 0 : }
181 :
182 : /** @return the addition of this pvp with an offset. @version 1.0 */
183 63 : const PixelViewport operator + ( const Vector2i& offset ) const
184 : {
185 63 : return PixelViewport( x+offset.x(), y+offset.y(), w, h );
186 : }
187 :
188 : /** @internal
189 : * @return the viewport which would provide this pixel viewport when
190 : * applied to the rhs pixel viewport.
191 : */
192 687 : Viewport operator / ( const PixelViewport& rhs ) const
193 : {
194 687 : if( *this == rhs )
195 0 : return Viewport::FULL;
196 :
197 687 : if( !rhs.hasArea( ))
198 : return Viewport( static_cast<float>( x ),
199 632 : static_cast<float>( y ), 0.f, 0.f );
200 :
201 55 : return Viewport( ( x - rhs.x )/ static_cast<float>( rhs.w ),
202 55 : ( y - rhs.y )/ static_cast<float>( rhs.h ),
203 : ( w )/ static_cast<float>( rhs.w ),
204 165 : ( h )/ static_cast<float>( rhs.h ));
205 : }
206 :
207 : /** @return this pvp minus an offset. @version 1.3.0 */
208 0 : const PixelViewport& operator -= ( const Vector2i& offset )
209 : {
210 0 : x -= offset.x();
211 0 : y -= offset.y();
212 0 : return *this;
213 : }
214 :
215 : /**
216 : * Perform the inverse operation of applying a pixel decomposition to
217 : * this pixel viewport.
218 : * @version 1.0
219 : */
220 0 : void unapply( const Pixel& pixel )
221 : {
222 0 : w *= pixel.w;
223 0 : h *= pixel.h;
224 0 : x += pixel.x;
225 0 : y += pixel.y;
226 0 : }
227 :
228 : /**
229 : * @return true if the two pixel viewports are identical.
230 : * @version 1.0
231 : */
232 1817 : bool operator == ( const PixelViewport& rhs ) const
233 : {
234 1817 : return ( x==rhs.x && y==rhs.y && w==rhs.w && h==rhs.h );
235 : }
236 :
237 : /**
238 : * @return true if the two pixel viewports are not identical.
239 : * @version 1.0
240 : */
241 5228 : bool operator != ( const PixelViewport& rhs ) const
242 : {
243 5228 : return ( x!=rhs.x || y!=rhs.y || w!=rhs.w || h!=rhs.h );
244 : }
245 :
246 : /**
247 : * Create a pixel viewport that includes both viewports (union).
248 : * @version 1.0
249 : */
250 64 : void merge( const PixelViewport& rhs )
251 : {
252 64 : if( *this == rhs || !rhs.isValid( ))
253 54 : return;
254 :
255 10 : if( !hasArea( ))
256 : {
257 10 : *this = rhs;
258 10 : return;
259 : }
260 0 : if( !rhs.hasArea( ))
261 0 : return;
262 :
263 0 : const int32_t sEx = x + w;
264 0 : const int32_t sEy = y + h;
265 0 : const int32_t dEx = rhs.x + rhs.w;
266 0 : const int32_t dEy = rhs.y + rhs.h;
267 :
268 0 : x = LB_MIN( x, rhs.x );
269 0 : y = LB_MIN( y, rhs.y );
270 0 : w = LB_MAX( sEx, dEx ) - x;
271 0 : h = LB_MAX( sEy, dEy ) - y;
272 : }
273 :
274 : /** Create the intersection of the two pixel viewports. @version 1.0 */
275 0 : void intersect( const PixelViewport& rhs )
276 : {
277 0 : if( *this == rhs )
278 0 : return;
279 :
280 0 : if( !rhs.isValid() || !isValid() )
281 : {
282 0 : invalidate();
283 0 : return;
284 : }
285 :
286 0 : if( !rhs.hasArea() || !hasArea() )
287 : {
288 0 : x = 0;
289 0 : y = 0;
290 0 : w = 0;
291 0 : h = 0;
292 0 : return;
293 : }
294 :
295 0 : const int32_t sEx = x + w;
296 0 : const int32_t sEy = y + h;
297 0 : const int32_t dEx = rhs.x + rhs.w;
298 0 : const int32_t dEy = rhs.y + rhs.h;
299 :
300 0 : x = LB_MAX( x, rhs.x );
301 0 : y = LB_MAX( y, rhs.y );
302 0 : w = LB_MIN( sEx, dEx ) - x;
303 0 : h = LB_MIN( sEy, dEy ) - y;
304 : }
305 :
306 : //@}
307 :
308 : int32_t x;
309 : int32_t y;
310 : int32_t w;
311 : int32_t h;
312 : };
313 :
314 660 : inline std::ostream& operator << ( std::ostream& os,
315 : const PixelViewport& pvp )
316 : {
317 660 : os << "[ " << pvp.x << " " << pvp.y << " " << pvp.w << " " << pvp.h
318 660 : <<" ]";
319 660 : return os;
320 : }
321 : }
322 : }
323 :
324 : namespace lunchbox
325 : {
326 0 : template<> inline void byteswap( eq::fabric::PixelViewport& value )
327 : {
328 0 : byteswap( value.x );
329 0 : byteswap( value.y );
330 0 : byteswap( value.w );
331 0 : byteswap( value.h );
332 0 : }
333 : }
334 : #endif // EQFABRIC_PIXELVIEWPORT_H
|