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