1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 #include <osg/Camera>
14 #include <osg/RenderInfo>
15 #include <osg/Texture1D>
16 #include <osg/Texture2D>
17 #include <osg/Texture3D>
18 #include <osg/TextureRectangle>
19 #include <osg/TextureCubeMap>
20 #include <osg/Texture2DArray>
21 #include <osg/Notify>
22 
23 using namespace osg;
24 
25 const unsigned int Camera::FACE_CONTROLLED_BY_GEOMETRY_SHADER = 0xffffffff;
26 
Camera()27 Camera::Camera():
28     _view(0),
29     _allowEventFocus(true),
30     _clearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT),
31     _clearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f)),
32     _clearAccum(osg::Vec4(0.0f,0.0f,0.0f,1.0f)),
33     _clearDepth(1.0),
34     _clearStencil(0),
35     _transformOrder(PRE_MULTIPLY),
36     _projectionResizePolicy(HORIZONTAL),
37     _renderOrder(POST_RENDER),
38     _renderOrderNum(0),
39     _drawBuffer(GL_NONE),
40     _readBuffer(GL_NONE),
41     _renderTargetImplementation(FRAME_BUFFER),
42     _renderTargetFallback(FRAME_BUFFER),
43     _implicitBufferAttachmentRenderMask( USE_DISPLAY_SETTINGS_MASK ),
44     _implicitBufferAttachmentResolveMask( USE_DISPLAY_SETTINGS_MASK ),
45     _attachmentMapModifiedCount(0)
46 {
47     setStateSet(new StateSet);
48 }
49 
Camera(const Camera & camera,const CopyOp & copyop)50 Camera::Camera(const Camera& camera,const CopyOp& copyop):
51     Transform(camera,copyop),
52     CullSettings(camera),
53     _view(camera._view),
54     _allowEventFocus(camera._allowEventFocus),
55     _displaySettings(camera._displaySettings),
56     _clearMask(camera._clearMask),
57     _clearColor(camera._clearColor),
58     _clearAccum(camera._clearAccum),
59     _clearDepth(camera._clearDepth),
60     _clearStencil(camera._clearStencil),
61     _colorMask(camera._colorMask),
62     _viewport(camera._viewport),
63     _transformOrder(camera._transformOrder),
64     _projectionResizePolicy(camera._projectionResizePolicy),
65     _projectionMatrix(camera._projectionMatrix),
66     _viewMatrix(camera._viewMatrix),
67     _renderOrder(camera._renderOrder),
68     _renderOrderNum(camera._renderOrderNum),
69     _drawBuffer(camera._drawBuffer),
70     _readBuffer(camera._readBuffer),
71     _renderTargetImplementation(camera._renderTargetImplementation),
72     _renderTargetFallback(camera._renderTargetFallback),
73     _bufferAttachmentMap(camera._bufferAttachmentMap),
74     _implicitBufferAttachmentRenderMask(camera._implicitBufferAttachmentRenderMask),
75     _implicitBufferAttachmentResolveMask(camera._implicitBufferAttachmentResolveMask),
76     _attachmentMapModifiedCount(camera._attachmentMapModifiedCount),
77     _affinity(camera._affinity),
78     _initialDrawCallback(camera._initialDrawCallback),
79     _preDrawCallback(camera._preDrawCallback),
80     _postDrawCallback(camera._postDrawCallback),
81     _finalDrawCallback(camera._finalDrawCallback)
82 {
83     // need to copy/share graphics context?
84 }
85 
86 
~Camera()87 Camera::~Camera()
88 {
89     setCameraThread(0);
90 
91     if (_graphicsContext.valid()) _graphicsContext->removeCamera(this);
92 }
93 
operator ()(osg::RenderInfo & renderInfo) const94 void Camera::DrawCallback::operator () (osg::RenderInfo& renderInfo) const
95 {
96     if (renderInfo.getCurrentCamera())
97     {
98         operator()(*(renderInfo.getCurrentCamera()));
99     }
100     else
101     {
102         OSG_WARN<<"Error: Camera::DrawCallback called without valid camera."<<std::endl;
103     }
104 }
105 
106 
setGraphicsContext(GraphicsContext * context)107 void Camera::setGraphicsContext(GraphicsContext* context)
108 {
109     if (_graphicsContext == context) return;
110 
111     if (_graphicsContext.valid()) _graphicsContext->removeCamera(this);
112 
113     _graphicsContext = context;
114 
115     if (_graphicsContext.valid()) _graphicsContext->addCamera(this);
116 }
117 
118 
isRenderToTextureCamera() const119 bool Camera::isRenderToTextureCamera() const
120 {
121     return (!_bufferAttachmentMap.empty());
122 }
123 
setRenderTargetImplementation(RenderTargetImplementation impl)124 void Camera::setRenderTargetImplementation(RenderTargetImplementation impl)
125 {
126     _renderTargetImplementation = impl;
127     if (impl<FRAME_BUFFER) _renderTargetFallback = (RenderTargetImplementation)(impl+1);
128     else _renderTargetFallback = impl;
129 }
130 
setRenderTargetImplementation(RenderTargetImplementation impl,RenderTargetImplementation fallback)131 void Camera::setRenderTargetImplementation(RenderTargetImplementation impl, RenderTargetImplementation fallback)
132 {
133     if (impl<fallback || (impl==FRAME_BUFFER && fallback==FRAME_BUFFER))
134     {
135         _renderTargetImplementation = impl;
136         _renderTargetFallback = fallback;
137     }
138     else
139     {
140         OSG_NOTICE<<"Warning: Camera::setRenderTargetImplementation(impl,fallback) must have a lower rated fallback than the main target implementation."<<std::endl;
141         setRenderTargetImplementation(impl);
142     }
143 }
144 
setColorMask(osg::ColorMask * colorMask)145 void Camera::setColorMask(osg::ColorMask* colorMask)
146 {
147     if (_colorMask == colorMask) return;
148 
149     osg::StateSet* stateset = getOrCreateStateSet();
150     if (_colorMask.valid() && stateset)
151     {
152         stateset->removeAttribute(_colorMask.get());
153     }
154 
155     _colorMask = colorMask;
156 
157     if (_colorMask.valid() && stateset)
158     {
159         stateset->setAttribute(_colorMask.get());
160     }
161 }
162 
setColorMask(bool red,bool green,bool blue,bool alpha)163 void Camera::setColorMask(bool red, bool green, bool blue, bool alpha)
164 {
165     if (!_colorMask) setColorMask(new osg::ColorMask);
166     if (_colorMask.valid()) _colorMask->setMask(red,green,blue,alpha);
167 }
168 
setViewport(osg::Viewport * viewport)169 void Camera::setViewport(osg::Viewport* viewport)
170 {
171     if (_viewport == viewport) return;
172 
173     osg::StateSet* stateset = getOrCreateStateSet();
174     if (_viewport.valid() && stateset)
175     {
176         stateset->removeAttribute(_viewport.get());
177     }
178 
179     _viewport = viewport;
180 
181     if (_viewport.valid() && stateset)
182     {
183         stateset->setAttribute(_viewport.get());
184     }
185 }
186 
setViewport(int x,int y,int width,int height)187 void Camera::setViewport(int x,int y,int width,int height)
188 {
189     if (!_viewport) setViewport(new osg::Viewport);
190     if (_viewport.valid()) _viewport->setViewport(x,y,width,height);
191 }
192 
getInverseViewMatrix() const193 Matrixd Camera::getInverseViewMatrix() const
194 {
195     Matrixd inverse;
196     inverse.invert(_viewMatrix);
197     return inverse;
198 }
setProjectionMatrixAsOrtho(double left,double right,double bottom,double top,double zNear,double zFar)199 void Camera::setProjectionMatrixAsOrtho(double left, double right,
200                                            double bottom, double top,
201                                            double zNear, double zFar)
202 {
203     setProjectionMatrix(osg::Matrixd::ortho(left, right,
204                                            bottom, top,
205                                            zNear, zFar));
206 }
207 
setProjectionMatrixAsOrtho2D(double left,double right,double bottom,double top)208 void Camera::setProjectionMatrixAsOrtho2D(double left, double right,
209                                              double bottom, double top)
210 {
211     setProjectionMatrix(osg::Matrixd::ortho2D(left, right,
212                                              bottom, top));
213 }
214 
setProjectionMatrixAsFrustum(double left,double right,double bottom,double top,double zNear,double zFar)215 void Camera::setProjectionMatrixAsFrustum(double left, double right,
216                                              double bottom, double top,
217                                              double zNear, double zFar)
218 {
219     setProjectionMatrix(osg::Matrixd::frustum(left, right,
220                                              bottom, top,
221                                              zNear, zFar));
222 }
223 
setProjectionMatrixAsPerspective(double fovy,double aspectRatio,double zNear,double zFar)224 void Camera::setProjectionMatrixAsPerspective(double fovy,double aspectRatio,
225                                                  double zNear, double zFar)
226 {
227     setProjectionMatrix(osg::Matrixd::perspective(fovy,aspectRatio,
228                                                  zNear, zFar));
229 }
230 
getProjectionMatrixAsOrtho(double & left,double & right,double & bottom,double & top,double & zNear,double & zFar) const231 bool Camera::getProjectionMatrixAsOrtho(double& left, double& right,
232                                            double& bottom, double& top,
233                                            double& zNear, double& zFar) const
234 {
235     return _projectionMatrix.getOrtho(left, right,
236                                        bottom, top,
237                                        zNear, zFar);
238 }
239 
getProjectionMatrixAsFrustum(double & left,double & right,double & bottom,double & top,double & zNear,double & zFar) const240 bool Camera::getProjectionMatrixAsFrustum(double& left, double& right,
241                                              double& bottom, double& top,
242                                              double& zNear, double& zFar) const
243 {
244     return _projectionMatrix.getFrustum(left, right,
245                                          bottom, top,
246                                          zNear, zFar);
247 }
248 
getProjectionMatrixAsPerspective(double & fovy,double & aspectRatio,double & zNear,double & zFar) const249 bool Camera::getProjectionMatrixAsPerspective(double& fovy,double& aspectRatio,
250                                                  double& zNear, double& zFar) const
251 {
252     return _projectionMatrix.getPerspective(fovy, aspectRatio, zNear, zFar);
253 }
254 
setViewMatrixAsLookAt(const Vec3d & eye,const Vec3d & center,const Vec3d & up)255 void Camera::setViewMatrixAsLookAt(const Vec3d& eye,const Vec3d& center,const Vec3d& up)
256 {
257     setViewMatrix(osg::Matrixd::lookAt(eye,center,up));
258 }
259 
getViewMatrixAsLookAt(Vec3d & eye,Vec3d & center,Vec3d & up,double lookDistance) const260 void Camera::getViewMatrixAsLookAt(Vec3d& eye,Vec3d& center,Vec3d& up,double lookDistance) const
261 {
262     _viewMatrix.getLookAt(eye,center,up,lookDistance);
263 }
264 
getViewMatrixAsLookAt(Vec3f & eye,Vec3f & center,Vec3f & up,float lookDistance) const265 void Camera::getViewMatrixAsLookAt(Vec3f& eye,Vec3f& center,Vec3f& up,float lookDistance) const
266 {
267     _viewMatrix.getLookAt(eye,center,up,lookDistance);
268 }
269 
270 
attach(BufferComponent buffer,GLenum internalFormat)271 void Camera::attach(BufferComponent buffer, GLenum internalFormat)
272 {
273     switch(buffer)
274     {
275     case DEPTH_BUFFER:
276         if(_bufferAttachmentMap.find(PACKED_DEPTH_STENCIL_BUFFER) != _bufferAttachmentMap.end())
277         {
278             OSG_WARN << "Camera: DEPTH_BUFFER already attached as PACKED_DEPTH_STENCIL_BUFFER !" << std::endl;
279         }
280         break;
281 
282     case STENCIL_BUFFER:
283         if(_bufferAttachmentMap.find(PACKED_DEPTH_STENCIL_BUFFER) != _bufferAttachmentMap.end())
284         {
285             OSG_WARN << "Camera: STENCIL_BUFFER already attached as PACKED_DEPTH_STENCIL_BUFFER !" << std::endl;
286         }
287         break;
288 
289     case PACKED_DEPTH_STENCIL_BUFFER:
290         if(_bufferAttachmentMap.find(DEPTH_BUFFER) != _bufferAttachmentMap.end())
291         {
292             OSG_WARN << "Camera: DEPTH_BUFFER already attached !" << std::endl;
293         }
294         if(_bufferAttachmentMap.find(STENCIL_BUFFER) != _bufferAttachmentMap.end())
295         {
296             OSG_WARN << "Camera: STENCIL_BUFFER already attached !" << std::endl;
297         }
298         break;
299     default:
300         break;
301     }
302     _bufferAttachmentMap[buffer]._internalFormat = internalFormat;
303 }
304 
attach(BufferComponent buffer,osg::Texture * texture,unsigned int level,unsigned int face,bool mipMapGeneration,unsigned int multisampleSamples,unsigned int multisampleColorSamples)305 void Camera::attach(BufferComponent buffer, osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration,
306                     unsigned int multisampleSamples,
307                     unsigned int multisampleColorSamples)
308 {
309     _bufferAttachmentMap[buffer]._texture = texture;
310     _bufferAttachmentMap[buffer]._level = level;
311     _bufferAttachmentMap[buffer]._face = face;
312     _bufferAttachmentMap[buffer]._mipMapGeneration = mipMapGeneration;
313     _bufferAttachmentMap[buffer]._multisampleSamples = multisampleSamples;
314     _bufferAttachmentMap[buffer]._multisampleColorSamples = multisampleColorSamples;
315 }
316 
attach(BufferComponent buffer,osg::Image * image,unsigned int multisampleSamples,unsigned int multisampleColorSamples)317 void Camera::attach(BufferComponent buffer, osg::Image* image,
318                     unsigned int multisampleSamples,
319                     unsigned int multisampleColorSamples)
320 {
321     _bufferAttachmentMap[buffer]._image = image;
322     _bufferAttachmentMap[buffer]._multisampleSamples = multisampleSamples;
323     _bufferAttachmentMap[buffer]._multisampleColorSamples = multisampleColorSamples;
324 }
325 
detach(BufferComponent buffer)326 void Camera::detach(BufferComponent buffer)
327 {
328     _bufferAttachmentMap.erase(buffer);
329 }
330 
resizeGLObjectBuffers(unsigned int maxSize)331 void Camera::resizeGLObjectBuffers(unsigned int maxSize)
332 {
333     if (_renderer.valid()) _renderer->resizeGLObjectBuffers(maxSize);
334     if (_renderingCache.valid()) _renderingCache->resizeGLObjectBuffers(maxSize);
335 
336     if (_initialDrawCallback.valid()) _initialDrawCallback->resizeGLObjectBuffers(maxSize);
337     if (_preDrawCallback.valid()) _preDrawCallback->resizeGLObjectBuffers(maxSize);
338     if (_postDrawCallback.valid()) _postDrawCallback->resizeGLObjectBuffers(maxSize);
339     if (_finalDrawCallback.valid()) _finalDrawCallback->resizeGLObjectBuffers(maxSize);
340 
341     Transform::resizeGLObjectBuffers(maxSize);
342 }
343 
releaseGLObjects(osg::State * state) const344 void Camera::releaseGLObjects(osg::State* state) const
345 {
346     if (_renderer.valid()) _renderer->releaseGLObjects(state);
347     if (_renderingCache.valid()) _renderingCache->releaseGLObjects(state);
348 
349     if (_initialDrawCallback.valid()) _initialDrawCallback->releaseGLObjects(state);
350     if (_preDrawCallback.valid()) _preDrawCallback->releaseGLObjects(state);
351     if (_postDrawCallback.valid()) _postDrawCallback->releaseGLObjects(state);
352     if (_finalDrawCallback.valid()) _finalDrawCallback->releaseGLObjects(state);
353 
354     Transform::releaseGLObjects(state);
355 }
356 
357 
computeLocalToWorldMatrix(Matrix & matrix,NodeVisitor *) const358 bool Camera::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const
359 {
360     if (_referenceFrame==RELATIVE_RF)
361     {
362         if (_transformOrder==PRE_MULTIPLY)
363         {
364             matrix.preMult(_viewMatrix);
365         }
366         else
367         {
368             matrix.postMult(_viewMatrix);
369         }
370     }
371     else // absolute
372     {
373         matrix = _viewMatrix;
374     }
375     return true;
376 }
377 
computeWorldToLocalMatrix(Matrix & matrix,NodeVisitor *) const378 bool Camera::computeWorldToLocalMatrix(Matrix& matrix,NodeVisitor*) const
379 {
380     const Matrixd& inverse = getInverseViewMatrix();
381 
382     if (_referenceFrame==RELATIVE_RF)
383     {
384         if (_transformOrder==PRE_MULTIPLY)
385         {
386             // note doing inverse so pre becomes post.
387             matrix.postMult(inverse);
388         }
389         else
390         {
391             // note doing inverse so post becomes pre.
392             matrix.preMult(inverse);
393         }
394     }
395     else // absolute
396     {
397         matrix = inverse;
398     }
399     return true;
400 }
401 
inheritCullSettings(const CullSettings & settings,unsigned int inheritanceMask)402 void Camera::inheritCullSettings(const CullSettings& settings, unsigned int inheritanceMask)
403 {
404     CullSettings::inheritCullSettings(settings, inheritanceMask);
405 
406     const Camera* camera = dynamic_cast<const Camera*>(&settings);
407     if (camera)
408     {
409         //OSG_NOTICE<<"Inheriting slave Camera"<<std::endl;
410         if (inheritanceMask & CLEAR_COLOR)
411             _clearColor = camera->_clearColor;
412 
413         if (inheritanceMask & CLEAR_MASK)
414             _clearMask = camera->_clearMask;
415 
416         if (inheritanceMask & DRAW_BUFFER)
417             _drawBuffer = camera->_drawBuffer;
418 
419         if (inheritanceMask & READ_BUFFER)
420             _readBuffer = camera->_readBuffer;
421     }
422 }
423 
resizeAttachments(int width,int height)424 void Camera::resizeAttachments(int width, int height)
425 {
426     bool modified = false;
427     for(BufferAttachmentMap::iterator itr = _bufferAttachmentMap.begin();
428         itr != _bufferAttachmentMap.end();
429         ++itr)
430     {
431         Attachment& attachment = itr->second;
432         if (attachment._texture.valid())
433         {
434             {
435                 osg::Texture1D* texture = dynamic_cast<osg::Texture1D*>(attachment._texture.get());
436                 if (texture && (texture->getTextureWidth()!=width))
437                 {
438                     modified = true;
439                     texture->setTextureWidth(width);
440                     texture->dirtyTextureObject();
441                 }
442             }
443 
444             {
445                 osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(attachment._texture.get());
446                 if (texture && ((texture->getTextureWidth()!=width) || (texture->getTextureHeight()!=height)))
447                 {
448                     modified = true;
449                     texture->setTextureSize(width, height);
450                     texture->dirtyTextureObject();
451                 }
452             }
453 
454             {
455                 osg::Texture3D* texture = dynamic_cast<osg::Texture3D*>(attachment._texture.get());
456                 if (texture && ((texture->getTextureWidth()!=width) || (texture->getTextureHeight()!=height)))
457                 {
458                     modified = true;
459                     texture->setTextureSize(width, height, texture->getTextureDepth());
460                     texture->dirtyTextureObject();
461                 }
462             }
463 
464             {
465                 osg::Texture2DArray* texture = dynamic_cast<osg::Texture2DArray*>(attachment._texture.get());
466                 if (texture && ((texture->getTextureWidth()!=width) || (texture->getTextureHeight()!=height)))
467                 {
468                     modified = true;
469                     texture->setTextureSize(width, height, texture->getTextureDepth());
470                     texture->dirtyTextureObject();
471                 }
472             }
473         }
474 
475         if (attachment._image.valid() && (attachment._image->s()!=width || attachment._image->s()!=height) )
476         {
477             modified = true;
478             osg::Image* image = attachment._image.get();
479             image->allocateImage(width, height, image->r(),
480                                  image->getPixelFormat(), image->getDataType(),
481                                  image->getPacking());
482         }
483     }
484 
485     if (modified)
486     {
487         dirtyAttachmentMap();
488     }
489 }
490 
resize(int width,int height,int resizeMask)491 void Camera::resize(int width, int height, int resizeMask)
492 {
493     if (getViewport())
494     {
495         double previousWidth = getViewport()->width();
496         double previousHeight = getViewport()->height();
497         double newWidth = width;
498         double newHeight = height;
499 
500         if ((previousWidth!=newWidth) || (previousHeight!=newHeight))
501         {
502             if ((resizeMask&RESIZE_PROJECTIONMATRIX)!=0 && (getProjectionResizePolicy()!=FIXED))
503             {
504                 double widthChangeRatio = newWidth / previousWidth;
505                 double heigtChangeRatio = newHeight / previousHeight;
506                 double aspectRatioChange = widthChangeRatio / heigtChangeRatio;
507                 if (aspectRatioChange!=1.0)
508                 {
509                     switch(getProjectionResizePolicy())
510                     {
511                         case(HORIZONTAL): getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0); break;
512                         case(VERTICAL): getProjectionMatrix() *= osg::Matrix::scale(1.0, aspectRatioChange,1.0); break;
513                         case(FIXED): break;
514                     }
515                 }
516             }
517 
518             if ((resizeMask&RESIZE_VIEWPORT)!=0)
519             {
520                 setViewport(0,0,width, height);
521             }
522         }
523     }
524 
525     if ((resizeMask&RESIZE_ATTACHMENTS)!=0)
526     {
527         resizeAttachments(width, height);
528     }
529 }
530 
setProcessorAffinity(const OpenThreads::Affinity & affinity)531 void Camera::setProcessorAffinity(const OpenThreads::Affinity& affinity)
532 {
533     _affinity = affinity;
534 
535     if (_cameraThread.valid()) _cameraThread->setProcessorAffinity(affinity);
536 }
537 
createCameraThread()538 void Camera::createCameraThread()
539 {
540     if (!_cameraThread)
541     {
542         setCameraThread(new OperationThread);
543     }
544 }
545 
setCameraThread(OperationThread * gt)546 void Camera::setCameraThread(OperationThread* gt)
547 {
548     if (_cameraThread==gt) return;
549 
550     if (_cameraThread.valid())
551     {
552         // need to kill the thread in some way...
553         _cameraThread->cancel();
554         _cameraThread->setParent(0);
555     }
556 
557     _cameraThread = gt;
558 
559     if (_cameraThread.valid())
560     {
561         _cameraThread->setProcessorAffinity(_affinity);
562         _cameraThread->setParent(this);
563     }
564 }
565 
566 
567