Line data Source code
1 :
2 : /* Copyright (c) 2006-2013, 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 21028 : PixelViewport() : x(0), y(0), w(-1), h(-1) {}
41 :
42 : /** Construct a new pixel viewport with default values. @version 1.0 */
43 1299 : explicit PixelViewport( const int32_t x_, const int32_t y_,
44 : const int32_t w_, const int32_t h_ )
45 1299 : : x(x_), y(y_), w(w_), h(h_) {}
46 :
47 : /** Construct a new pixel viewport with default values. @version 1.1.6*/
48 21 : explicit PixelViewport( const int32_t pvp[4] )
49 21 : : 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 909 : 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 6125 : 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 4680 : bool hasArea() const { return (w>0 && h>0); }
70 :
71 : /** @return the area in pixels. @version 1.0 */
72 1959 : 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 3735 : void apply( const Viewport& rhs )
90 : {
91 : // honor position over size to avoid rounding artifacts
92 3735 : const int32_t xEnd = x + static_cast<int32_t>((rhs.x+rhs.w)*w);
93 3735 : const int32_t yEnd = y + static_cast<int32_t>((rhs.y+rhs.h)*h);
94 :
95 3735 : x += static_cast<int32_t>( w * rhs.x );
96 3735 : y += static_cast<int32_t>( h * rhs.y );
97 3735 : w = xEnd - x;
98 3735 : h = yEnd - y;
99 3735 : }
100 :
101 : /** Apply a pixel decomposition to this pixel viewport. @internal */
102 1164 : void apply( const Pixel& pixel )
103 : {
104 1164 : 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 1164 : 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 1164 : }
127 :
128 : /** Apply a zoom to this pixel viewport. @internal */
129 1166 : void apply( const Zoom& zoom )
130 : {
131 1166 : if( zoom == Zoom::NONE )
132 2332 : 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 1164 : const Zoom getZoom( const PixelViewport& rhs ) const
146 : {
147 1164 : if( *this == rhs )
148 1164 : 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 1934 : int32_t getXEnd() const { return x+w; }
160 :
161 : /** @return the Y end position. @version 1.0 */
162 1934 : int32_t getYEnd() const { return y+h; }
163 :
164 : /** Convert into a lunchbox::Plugin usable format. @version 1.5.2 */
165 278 : void convertToPlugin( uint64_t dims[4] ) const
166 : {
167 278 : dims[ 0 ] = x;
168 278 : dims[ 1 ] = w;
169 278 : dims[ 2 ] = y;
170 278 : dims[ 3 ] = h;
171 278 : }
172 :
173 : /** Convert from a lunchbox::Plugin format. @version 1.5.2 */
174 3 : void convertFromPlugin( const uint64_t dims[4] )
175 : {
176 3 : x = int32_t( dims[ 0 ]);
177 3 : w = int32_t( dims[ 1 ]);
178 3 : y = int32_t( dims[ 2 ]);
179 3 : h = int32_t( dims[ 3 ]);
180 3 : }
181 :
182 : /** @return the addition of this pvp with an offset. @version 1.0 */
183 69 : const PixelViewport operator + ( const Vector2i& offset ) const
184 : {
185 69 : 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 1333 : Viewport operator / ( const PixelViewport& rhs ) const
193 : {
194 1333 : if( *this == rhs )
195 979 : return Viewport::FULL;
196 :
197 354 : if( !rhs.hasArea( ))
198 : return Viewport( static_cast<float>( x ),
199 309 : static_cast<float>( y ), 0.f, 0.f );
200 :
201 45 : return Viewport( ( x - rhs.x )/ static_cast<float>( rhs.w ),
202 45 : ( y - rhs.y )/ static_cast<float>( rhs.h ),
203 : ( w )/ static_cast<float>( rhs.w ),
204 135 : ( h )/ static_cast<float>( rhs.h ));
205 : }
206 :
207 : /** @return this pvp minus an offset. @version 1.3.0 */
208 2 : const PixelViewport& operator -= ( const Vector2i& offset )
209 : {
210 2 : x -= offset.x();
211 2 : y -= offset.y();
212 2 : 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 3203 : bool operator == ( const PixelViewport& rhs ) const
233 : {
234 3203 : 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 4384 : bool operator != ( const PixelViewport& rhs ) const
242 : {
243 4384 : 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 84 : void merge( const PixelViewport& rhs )
251 : {
252 84 : if( *this == rhs || !rhs.hasArea() )
253 54 : return;
254 :
255 30 : if( !hasArea() )
256 : {
257 30 : *this = rhs;
258 30 : return;
259 : }
260 :
261 0 : const int32_t sEx = x + w;
262 0 : const int32_t sEy = y + h;
263 0 : const int32_t dEx = rhs.x + rhs.w;
264 0 : const int32_t dEy = rhs.y + rhs.h;
265 :
266 0 : x = LB_MIN( x, rhs.x );
267 0 : y = LB_MIN( y, rhs.y );
268 0 : w = LB_MAX( sEx, dEx ) - x;
269 0 : h = LB_MAX( sEy, dEy ) - y;
270 : }
271 :
272 : /** Create the intersection of the two pixel viewports. @version 1.0 */
273 9 : void intersect( const PixelViewport& rhs )
274 : {
275 9 : if( *this == rhs )
276 9 : return;
277 :
278 0 : if( !rhs.isValid() || !isValid() )
279 : {
280 0 : invalidate();
281 0 : return;
282 : }
283 :
284 0 : if( !rhs.hasArea() || !hasArea() )
285 : {
286 0 : x = 0;
287 0 : y = 0;
288 0 : w = 0;
289 0 : h = 0;
290 0 : return;
291 : }
292 :
293 0 : const int32_t sEx = x + w;
294 0 : const int32_t sEy = y + h;
295 0 : const int32_t dEx = rhs.x + rhs.w;
296 0 : const int32_t dEy = rhs.y + rhs.h;
297 :
298 0 : x = LB_MAX( x, rhs.x );
299 0 : y = LB_MAX( y, rhs.y );
300 0 : w = LB_MIN( sEx, dEx ) - x;
301 0 : h = LB_MIN( sEy, dEy ) - y;
302 : }
303 :
304 : //@}
305 :
306 : int32_t x;
307 : int32_t y;
308 : int32_t w;
309 : int32_t h;
310 : };
311 :
312 379 : inline std::ostream& operator << ( std::ostream& os,
313 : const PixelViewport& pvp )
314 : {
315 379 : os << "[ " << pvp.x << " " << pvp.y << " " << pvp.w << " " << pvp.h
316 379 : <<" ]";
317 379 : return os;
318 : }
319 : }
320 : }
321 :
322 : namespace lunchbox
323 : {
324 0 : template<> inline void byteswap( eq::fabric::PixelViewport& value )
325 : {
326 0 : byteswap( value.x );
327 0 : byteswap( value.y );
328 0 : byteswap( value.w );
329 0 : byteswap( value.h );
330 0 : }
331 : }
332 : #endif // EQFABRIC_PIXELVIEWPORT_H
|