1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Renderer/BsCamera.h"
4#include "Private/RTTI/BsCameraRTTI.h"
5#include "Math/BsMath.h"
6#include "Math/BsMatrix3.h"
7#include "Math/BsVector2.h"
8#include "Math/BsAABox.h"
9#include "Math/BsSphere.h"
10#include "Error/BsException.h"
11#include "RenderAPI/BsRenderAPI.h"
12#include "Scene/BsSceneObject.h"
13#include "Renderer/BsRendererManager.h"
14#include "Renderer/BsRenderer.h"
15#include "Scene/BsSceneManager.h"
16#include "CoreThread/BsCoreObjectSync.h"
17
18namespace bs
19{
20 const float CameraBase::INFINITE_FAR_PLANE_ADJUST = 0.00001f;
21
22 CameraBase::CameraBase()
23 : mRecalcFrustum(true), mRecalcFrustumPlanes(true), mRecalcView(true)
24 {
25 mRenderSettings = bs_shared_ptr_new<RenderSettings>();
26
27 invalidateFrustum();
28 }
29
30 void CameraBase::setHorzFOV(const Radian& fov)
31 {
32 mHorzFOV = fov;
33 invalidateFrustum();
34 _markCoreDirty();
35 }
36
37 const Radian& CameraBase::getHorzFOV() const
38 {
39 return mHorzFOV;
40 }
41
42 void CameraBase::setFarClipDistance(float farPlane)
43 {
44 mFarDist = farPlane;
45 invalidateFrustum();
46 _markCoreDirty();
47 }
48
49 float CameraBase::getFarClipDistance() const
50 {
51 return mFarDist;
52 }
53
54 void CameraBase::setNearClipDistance(float nearPlane)
55 {
56 if (nearPlane <= 0)
57 {
58 LOGERR("Near clip distance must be greater than zero.");
59 return;
60 }
61
62 mNearDist = nearPlane;
63 invalidateFrustum();
64 _markCoreDirty();
65 }
66
67 float CameraBase::getNearClipDistance() const
68 {
69 return mNearDist;
70 }
71
72 const Matrix4& CameraBase::getProjectionMatrix() const
73 {
74 updateFrustum();
75
76 return mProjMatrix;
77 }
78
79 const Matrix4& CameraBase::getProjectionMatrixInv() const
80 {
81 updateFrustum();
82
83 return mProjMatrixInv;
84 }
85
86 const Matrix4& CameraBase::getProjectionMatrixRS() const
87 {
88 updateFrustum();
89
90 return mProjMatrixRS;
91 }
92
93 const Matrix4& CameraBase::getProjectionMatrixRSInv() const
94 {
95 updateFrustum();
96
97 return mProjMatrixRSInv;
98 }
99
100 const Matrix4& CameraBase::getViewMatrix() const
101 {
102 updateView();
103
104 return mViewMatrix;
105 }
106
107 const Matrix4& CameraBase::getViewMatrixInv() const
108 {
109 updateView();
110
111 return mViewMatrixInv;
112 }
113
114 const ConvexVolume& CameraBase::getFrustum() const
115 {
116 // Make any pending updates to the calculated frustum planes
117 updateFrustumPlanes();
118
119 return mFrustum;
120 }
121
122 ConvexVolume CameraBase::getWorldFrustum() const
123 {
124 const Vector<Plane>& frustumPlanes = getFrustum().getPlanes();
125
126 const Transform& tfrm = getTransform();
127
128 Matrix4 worldMatrix;
129 worldMatrix.setTRS(tfrm.getPosition(), tfrm.getRotation(), Vector3::ONE);
130
131 Vector<Plane> worldPlanes(frustumPlanes.size());
132 UINT32 i = 0;
133 for (auto& plane : frustumPlanes)
134 {
135 worldPlanes[i] = worldMatrix.multiplyAffine(plane);
136 i++;
137 }
138
139 return ConvexVolume(worldPlanes);
140 }
141
142 void CameraBase::calcProjectionParameters(float& left, float& right, float& bottom, float& top) const
143 {
144 if (mCustomProjMatrix)
145 {
146 // Convert clipspace corners to camera space
147 Matrix4 invProj = mProjMatrix.inverse();
148 Vector3 topLeft(-0.5f, 0.5f, 0.0f);
149 Vector3 bottomRight(0.5f, -0.5f, 0.0f);
150
151 topLeft = invProj.multiply(topLeft);
152 bottomRight = invProj.multiply(bottomRight);
153
154 left = topLeft.x;
155 top = topLeft.y;
156 right = bottomRight.x;
157 bottom = bottomRight.y;
158 }
159 else
160 {
161 if (mFrustumExtentsManuallySet)
162 {
163 left = mLeft;
164 right = mRight;
165 top = mTop;
166 bottom = mBottom;
167 }
168 else if (mProjType == PT_PERSPECTIVE)
169 {
170 Radian thetaX(mHorzFOV * 0.5f);
171 float tanThetaX = Math::tan(thetaX);
172 float tanThetaY = tanThetaX / mAspect;
173
174 float half_w = tanThetaX * mNearDist;
175 float half_h = tanThetaY * mNearDist;
176
177 left = -half_w;
178 right = half_w;
179 bottom = -half_h;
180 top = half_h;
181
182 mLeft = left;
183 mRight = right;
184 mTop = top;
185 mBottom = bottom;
186 }
187 else
188 {
189 float half_w = getOrthoWindowWidth() * 0.5f;
190 float half_h = getOrthoWindowHeight() * 0.5f;
191
192 left = -half_w;
193 right = half_w;
194 bottom = -half_h;
195 top = half_h;
196
197 mLeft = left;
198 mRight = right;
199 mTop = top;
200 mBottom = bottom;
201 }
202 }
203 }
204
205 void CameraBase::updateFrustum() const
206 {
207 if (isFrustumOutOfDate())
208 {
209 float left, right, bottom, top;
210
211 calcProjectionParameters(left, right, bottom, top);
212
213 if (!mCustomProjMatrix)
214 {
215 float inv_w = 1 / (right - left);
216 float inv_h = 1 / (top - bottom);
217 float inv_d = 1 / (mFarDist - mNearDist);
218
219 if (mProjType == PT_PERSPECTIVE)
220 {
221 float A = 2 * mNearDist * inv_w;
222 float B = 2 * mNearDist * inv_h;
223 float C = (right + left) * inv_w;
224 float D = (top + bottom) * inv_h;
225 float q, qn;
226
227 if (mFarDist == 0)
228 {
229 // Infinite far plane
230 q = CameraBase::INFINITE_FAR_PLANE_ADJUST - 1;
231 qn = mNearDist * (CameraBase::INFINITE_FAR_PLANE_ADJUST - 2);
232 }
233 else
234 {
235 q = -(mFarDist + mNearDist) * inv_d;
236 qn = -2 * (mFarDist * mNearDist) * inv_d;
237 }
238
239 mProjMatrix = Matrix4::ZERO;
240 mProjMatrix[0][0] = A;
241 mProjMatrix[0][2] = C;
242 mProjMatrix[1][1] = B;
243 mProjMatrix[1][2] = D;
244 mProjMatrix[2][2] = q;
245 mProjMatrix[2][3] = qn;
246 mProjMatrix[3][2] = -1;
247 }
248 else if (mProjType == PT_ORTHOGRAPHIC)
249 {
250 float A = 2 * inv_w;
251 float B = 2 * inv_h;
252 float C = -(right + left) * inv_w;
253 float D = -(top + bottom) * inv_h;
254 float q, qn;
255
256 if (mFarDist == 0)
257 {
258 // Can not do infinite far plane here, avoid divided zero only
259 q = -CameraBase::INFINITE_FAR_PLANE_ADJUST / mNearDist;
260 qn = -CameraBase::INFINITE_FAR_PLANE_ADJUST - 1;
261 }
262 else
263 {
264 q = -2 * inv_d;
265 qn = -(mFarDist + mNearDist) * inv_d;
266 }
267
268 mProjMatrix = Matrix4::ZERO;
269 mProjMatrix[0][0] = A;
270 mProjMatrix[0][3] = C;
271 mProjMatrix[1][1] = B;
272 mProjMatrix[1][3] = D;
273 mProjMatrix[2][2] = q;
274 mProjMatrix[2][3] = qn;
275 mProjMatrix[3][3] = 1;
276 }
277 }
278
279 ct::RenderAPI* renderAPI = ct::RenderAPI::instancePtr();
280 renderAPI->convertProjectionMatrix(mProjMatrix, mProjMatrixRS);
281 mProjMatrixInv = mProjMatrix.inverse();
282 mProjMatrixRSInv = mProjMatrixRS.inverse();
283
284 // Calculate bounding box (local)
285 // Box is from 0, down -Z, max dimensions as determined from far plane
286 // If infinite view frustum just pick a far value
287 float farDist = (mFarDist == 0) ? 100000 : mFarDist;
288
289 // Near plane bounds
290 Vector3 min(left, bottom, -farDist);
291 Vector3 max(right, top, 0);
292
293 if (mCustomProjMatrix)
294 {
295 // Some custom projection matrices can have unusual inverted settings
296 // So make sure the AABB is the right way around to start with
297 Vector3 tmp = min;
298 min.min(max);
299 max.max(tmp);
300 }
301
302 if (mProjType == PT_PERSPECTIVE)
303 {
304 // Merge with far plane bounds
305 float radio = farDist / mNearDist;
306 min.min(Vector3(left * radio, bottom * radio, -farDist));
307 max.max(Vector3(right * radio, top * radio, 0));
308 }
309
310 mBoundingBox.setExtents(min, max);
311
312 mRecalcFrustum = false;
313 mRecalcFrustumPlanes = true;
314 }
315 }
316
317 bool CameraBase::isFrustumOutOfDate() const
318 {
319 return mRecalcFrustum;
320 }
321
322 void CameraBase::updateView() const
323 {
324 if (!mCustomViewMatrix && mRecalcView)
325 {
326 mViewMatrix.makeView(mTransform.getPosition(), mTransform.getRotation());
327 mViewMatrixInv = mViewMatrix.inverseAffine();
328 mRecalcView = false;
329 }
330 }
331
332 void CameraBase::updateFrustumPlanes() const
333 {
334 updateFrustum();
335
336 if (mRecalcFrustumPlanes)
337 {
338 mFrustum = ConvexVolume(mProjMatrix);
339 mRecalcFrustumPlanes = false;
340 }
341 }
342
343 float CameraBase::getAspectRatio() const
344 {
345 return mAspect;
346 }
347
348 void CameraBase::setAspectRatio(float r)
349 {
350 mAspect = r;
351 invalidateFrustum();
352 _markCoreDirty();
353 }
354
355 const AABox& CameraBase::getBoundingBox() const
356 {
357 updateFrustum();
358
359 return mBoundingBox;
360 }
361
362 void CameraBase::setProjectionType(ProjectionType pt)
363 {
364 mProjType = pt;
365 invalidateFrustum();
366 _markCoreDirty();
367 }
368
369 ProjectionType CameraBase::getProjectionType() const
370 {
371 return mProjType;
372 }
373
374 void CameraBase::setCustomViewMatrix(bool enable, const Matrix4& viewMatrix)
375 {
376 mCustomViewMatrix = enable;
377 if (enable)
378 {
379 mViewMatrix = viewMatrix;
380 mViewMatrixInv = mViewMatrix.inverseAffine();
381 }
382
383 _markCoreDirty();
384 }
385
386 void CameraBase::setCustomProjectionMatrix(bool enable, const Matrix4& projMatrix)
387 {
388 mCustomProjMatrix = enable;
389
390 if (enable)
391 mProjMatrix = projMatrix;
392
393 invalidateFrustum();
394 _markCoreDirty();
395 }
396
397 void CameraBase::setOrthoWindow(float w, float h)
398 {
399 mOrthoHeight = h;
400 mAspect = w / h;
401
402 invalidateFrustum();
403 _markCoreDirty();
404 }
405
406 void CameraBase::setOrthoWindowHeight(float h)
407 {
408 mOrthoHeight = h;
409
410 invalidateFrustum();
411 _markCoreDirty();
412 }
413
414 void CameraBase::setOrthoWindowWidth(float w)
415 {
416 mOrthoHeight = w / mAspect;
417
418 invalidateFrustum();
419 _markCoreDirty();
420 }
421
422 float CameraBase::getOrthoWindowHeight() const
423 {
424 return mOrthoHeight;
425 }
426
427 float CameraBase::getOrthoWindowWidth() const
428 {
429 return mOrthoHeight * mAspect;
430 }
431
432 void CameraBase::setFrustumExtents(float left, float right, float top, float bottom)
433 {
434 mFrustumExtentsManuallySet = true;
435 mLeft = left;
436 mRight = right;
437 mTop = top;
438 mBottom = bottom;
439
440 invalidateFrustum();
441 _markCoreDirty();
442 }
443
444 void CameraBase::resetFrustumExtents()
445 {
446 mFrustumExtentsManuallySet = false;
447
448 invalidateFrustum();
449 _markCoreDirty();
450 }
451
452 void CameraBase::getFrustumExtents(float& outleft, float& outright, float& outtop, float& outbottom) const
453 {
454 updateFrustum();
455
456 outleft = mLeft;
457 outright = mRight;
458 outtop = mTop;
459 outbottom = mBottom;
460 }
461
462 void CameraBase::setTransform(const Transform& transform)
463 {
464 SceneActor::setTransform(transform);
465
466 mRecalcView = true;
467 }
468
469 void CameraBase::invalidateFrustum() const
470 {
471 mRecalcFrustum = true;
472 mRecalcFrustumPlanes = true;
473 }
474
475 Vector2I CameraBase::worldToScreenPoint(const Vector3& worldPoint) const
476 {
477 Vector2 ndcPoint = worldToNdcPoint(worldPoint);
478 return ndcToScreenPoint(ndcPoint);
479 }
480
481 Vector2 CameraBase::worldToNdcPoint(const Vector3& worldPoint) const
482 {
483 Vector3 viewPoint = worldToViewPoint(worldPoint);
484 return viewToNdcPoint(viewPoint);
485 }
486
487 Vector3 CameraBase::worldToViewPoint(const Vector3& worldPoint) const
488 {
489 return getViewMatrix().multiplyAffine(worldPoint);
490 }
491
492 Vector3 CameraBase::screenToWorldPoint(const Vector2I& screenPoint, float depth) const
493 {
494 Vector2 ndcPoint = screenToNdcPoint(screenPoint);
495 return ndcToWorldPoint(ndcPoint, depth);
496 }
497
498 Vector3 CameraBase::screenToWorldPointDeviceDepth(const Vector2I& screenPoint, float deviceDepth) const
499 {
500 Vector2 ndcPoint = screenToNdcPoint(screenPoint);
501 Vector4 worldPoint(ndcPoint.x, ndcPoint.y, deviceDepth, 1.0f);
502 worldPoint = getProjectionMatrixRS().inverse().multiply(worldPoint);
503
504 Vector3 worldPoint3D;
505 if (Math::abs(worldPoint.w) > 1e-7f)
506 {
507 float invW = 1.0f / worldPoint.w;
508
509 worldPoint3D.x = worldPoint.x * invW;
510 worldPoint3D.y = worldPoint.y * invW;
511 worldPoint3D.z = worldPoint.z * invW;
512 }
513
514 return viewToWorldPoint(worldPoint3D);
515 }
516
517 Vector3 CameraBase::screenToViewPoint(const Vector2I& screenPoint, float depth) const
518 {
519 Vector2 ndcPoint = screenToNdcPoint(screenPoint);
520 return ndcToViewPoint(ndcPoint, depth);
521 }
522
523 Vector2 CameraBase::screenToNdcPoint(const Vector2I& screenPoint) const
524 {
525 Rect2I viewport = getViewportRect();
526
527 Vector2 ndcPoint;
528 ndcPoint.x = (float)(((screenPoint.x - viewport.x) / (float)viewport.width) * 2.0f - 1.0f);
529
530 const Conventions& rapiConventions = ct::gCaps().conventions;
531 if(rapiConventions.ndcYAxis == Conventions::Axis::Down)
532 ndcPoint.y = (float)(((screenPoint.y - viewport.y) / (float)viewport.height) * 2.0f - 1.0f);
533 else
534 ndcPoint.y = (float)((1.0f - ((screenPoint.y - viewport.y) / (float)viewport.height)) * 2.0f - 1.0f);
535
536 return ndcPoint;
537 }
538
539 Vector3 CameraBase::viewToWorldPoint(const Vector3& viewPoint) const
540 {
541 return getViewMatrix().inverseAffine().multiplyAffine(viewPoint);
542 }
543
544 Vector2I CameraBase::viewToScreenPoint(const Vector3& viewPoint) const
545 {
546 Vector2 ndcPoint = viewToNdcPoint(viewPoint);
547 return ndcToScreenPoint(ndcPoint);
548 }
549
550 Vector2 CameraBase::viewToNdcPoint(const Vector3& viewPoint) const
551 {
552 Vector3 projPoint = projectPoint(viewPoint);
553
554 return Vector2(projPoint.x, projPoint.y);
555 }
556
557 Vector3 CameraBase::ndcToWorldPoint(const Vector2& ndcPoint, float depth) const
558 {
559 Vector3 viewPoint = ndcToViewPoint(ndcPoint, depth);
560 return viewToWorldPoint(viewPoint);
561 }
562
563 Vector3 CameraBase::ndcToViewPoint(const Vector2& ndcPoint, float depth) const
564 {
565 return unprojectPoint(Vector3(ndcPoint.x, ndcPoint.y, depth));
566 }
567
568 Vector2I CameraBase::ndcToScreenPoint(const Vector2& ndcPoint) const
569 {
570 Rect2I viewport = getViewportRect();
571
572 Vector2I screenPoint;
573 screenPoint.x = Math::roundToInt(viewport.x + ((ndcPoint.x + 1.0f) * 0.5f) * viewport.width);
574 screenPoint.y = Math::roundToInt(viewport.y + (1.0f - (ndcPoint.y + 1.0f) * 0.5f) * viewport.height);
575
576 return screenPoint;
577 }
578
579 Ray CameraBase::screenPointToRay(const Vector2I& screenPoint) const
580 {
581 Vector2 ndcPoint = screenToNdcPoint(screenPoint);
582
583 Vector3 near = unprojectPoint(Vector3(ndcPoint.x, ndcPoint.y, mNearDist));
584 Vector3 far = unprojectPoint(Vector3(ndcPoint.x, ndcPoint.y, mNearDist + 1.0f));
585
586 Ray ray(near, Vector3::normalize(far - near));
587 ray.transformAffine(getViewMatrix().inverseAffine());
588
589 return ray;
590 }
591
592 Vector3 CameraBase::projectPoint(const Vector3& point) const
593 {
594 Vector4 projPoint4(point.x, point.y, point.z, 1.0f);
595 projPoint4 = getProjectionMatrixRS().multiply(projPoint4);
596
597 if (Math::abs(projPoint4.w) > 1e-7f)
598 {
599 float invW = 1.0f / projPoint4.w;
600 projPoint4.x *= invW;
601 projPoint4.y *= invW;
602 projPoint4.z *= invW;
603 }
604 else
605 {
606 projPoint4.x = 0.0f;
607 projPoint4.y = 0.0f;
608 projPoint4.z = 0.0f;
609 }
610
611 return Vector3(projPoint4.x, projPoint4.y, projPoint4.z);
612 }
613
614 Vector3 CameraBase::unprojectPoint(const Vector3& point) const
615 {
616 // Point.z is expected to be in view space, so we need to do some extra work to get the proper coordinates
617 // (as opposed to if point.z was in device coordinates, in which case we could just inverse project)
618
619 // Get world position for a point near the far plane (0.95f)
620 Vector4 farAwayPoint(point.x, point.y, 0.95f, 1.0f);
621 farAwayPoint = getProjectionMatrixRS().inverse().multiply(farAwayPoint);
622
623 // Can't proceed if w is too small
624 if (Math::abs(farAwayPoint.w) > 1e-7f)
625 {
626 // Perspective divide, to get the values that make sense in 3D space
627 float invW = 1.0f / farAwayPoint.w;
628
629 Vector3 farAwayPoint3D;
630 farAwayPoint3D.x = farAwayPoint.x * invW;
631 farAwayPoint3D.y = farAwayPoint.y * invW;
632 farAwayPoint3D.z = farAwayPoint.z * invW;
633
634 // Find the distance to the far point along the camera's viewing axis
635 float distAlongZ = farAwayPoint3D.dot(-Vector3::UNIT_Z);
636
637 // Do nothing if point is behind the camera
638 if (distAlongZ >= 0.0f)
639 {
640 if (mProjType == PT_PERSPECTIVE)
641 {
642 // Direction from origin to our point
643 Vector3 dir = farAwayPoint3D; // Camera is at (0, 0, 0) so it's the same vector
644
645 // Our view space depth (point.z) is distance along the camera's viewing axis. Since our direction
646 // vector is not parallel to the viewing axis, instead of normalizing it with its own length, we
647 // "normalize" with the length projected along the camera's viewing axis.
648 dir /= distAlongZ;
649
650 // And now we just find the final position along the direction
651 return dir * point.z;
652 }
653 else // Ortographic
654 {
655 // Depth difference between our arbitrary point and actual depth
656 float depthDiff = distAlongZ - point.z;
657
658 // Depth difference along viewing direction
659 Vector3 depthDiffVec = depthDiff * -Vector3::UNIT_Z;
660
661 // Return point that is depthDiff closer than our arbitrary point
662 return farAwayPoint3D - depthDiffVec;
663 }
664 }
665 }
666
667 return Vector3(0.0f, 0.0f, 0.0f);
668 }
669
670 template <bool Core>
671 template <class P>
672 void TCamera<Core>::rttiEnumFields(P p)
673 {
674 p(mLayers);
675 p(mProjType);
676 p(mHorzFOV);
677 p(mFarDist);
678 p(mNearDist);
679 p(mAspect);
680 p(mOrthoHeight);
681 p(mPriority);
682 p(mCustomViewMatrix);
683 p(mCustomProjMatrix);
684 p(mFrustumExtentsManuallySet);
685 p(mMSAA);
686 p(mMain);
687 p(*mRenderSettings);
688 }
689
690 SPtr<ct::Camera> Camera::getCore() const
691 {
692 return std::static_pointer_cast<ct::Camera>(mCoreSpecific);
693 }
694
695 SPtr<Camera> Camera::create()
696 {
697 Camera* handler = new (bs_alloc<Camera>()) Camera();
698 SPtr<Camera> handlerPtr = bs_core_ptr<Camera>(handler);
699 handlerPtr->_setThisPtr(handlerPtr);
700 handlerPtr->initialize();
701
702 return handlerPtr;
703 }
704
705 SPtr<Camera> Camera::createEmpty()
706 {
707 Camera* handler = new (bs_alloc<Camera>()) Camera();
708 SPtr<Camera> handlerPtr = bs_core_ptr<Camera>(handler);
709 handlerPtr->_setThisPtr(handlerPtr);
710
711 return handlerPtr;
712 }
713
714 SPtr<ct::CoreObject> Camera::createCore() const
715 {
716 ct::Camera* handler = new (bs_alloc<ct::Camera>()) ct::Camera(mViewport->getCore());
717 SPtr<ct::Camera> handlerPtr = bs_shared_ptr<ct::Camera>(handler);
718 handlerPtr->_setThisPtr(handlerPtr);
719
720 return handlerPtr;
721 }
722
723 void Camera::initialize()
724 {
725 mViewport = Viewport::create(nullptr);
726
727 CoreObject::initialize();
728
729 gSceneManager()._registerCamera(std::static_pointer_cast<Camera>(getThisPtr()));
730 }
731
732 void Camera::destroy()
733 {
734 if(isInitialized())
735 gSceneManager()._unregisterCamera(std::static_pointer_cast<Camera>(getThisPtr()));
736
737 CoreObject::destroy();
738 }
739
740 void Camera::setMain(bool main)
741 {
742 mMain = main;
743 gSceneManager()._notifyMainCameraStateChanged(std::static_pointer_cast<Camera>(getThisPtr()));
744 }
745
746 Rect2I Camera::getViewportRect() const
747 {
748 return mViewport->getPixelArea();
749 }
750
751 CoreSyncData Camera::syncToCore(FrameAlloc* allocator)
752 {
753 UINT32 dirtyFlag = getCoreDirtyFlags();
754
755 UINT32 size = rttiGetElemSize(dirtyFlag);
756 size += coreSyncGetElemSize((SceneActor&)*this);
757
758 if (dirtyFlag != (UINT32)ActorDirtyFlag::Transform)
759 size += coreSyncGetElemSize(*this);
760
761 UINT8* buffer = allocator->alloc(size);
762
763 char* dataPtr = (char*)buffer;
764 dataPtr = rttiWriteElem(dirtyFlag, dataPtr);
765 dataPtr = coreSyncWriteElem((SceneActor&)*this, dataPtr);
766
767 if (dirtyFlag != (UINT32)ActorDirtyFlag::Transform)
768 dataPtr = coreSyncWriteElem(*this, dataPtr);
769
770 return CoreSyncData(buffer, size);
771 }
772
773 void Camera::getCoreDependencies(Vector<CoreObject*>& dependencies)
774 {
775 dependencies.push_back(mViewport.get());
776 }
777
778 void Camera::_markCoreDirty(ActorDirtyFlag flag)
779 {
780 markCoreDirty((UINT32)flag);
781 }
782
783 RTTITypeBase* Camera::getRTTIStatic()
784 {
785 return CameraRTTI::instance();
786 }
787
788 RTTITypeBase* Camera::getRTTI() const
789 {
790 return Camera::getRTTIStatic();
791 }
792
793 namespace ct
794 {
795 Camera::~Camera()
796 {
797 RendererManager::instance().getActive()->notifyCameraRemoved(this);
798 }
799
800 Camera::Camera(SPtr<RenderTarget> target, float left, float top, float width, float height)
801 : mRendererId(0)
802 {
803 mViewport = Viewport::create(target, left, top, width, height);
804 }
805
806 Camera::Camera(const SPtr<Viewport>& viewport)
807 : mRendererId(0)
808 {
809 mViewport = viewport;
810 }
811
812 void Camera::initialize()
813 {
814 RendererManager::instance().getActive()->notifyCameraAdded(this);
815
816 CoreObject::initialize();
817 }
818
819 Rect2I Camera::getViewportRect() const
820 {
821 return mViewport->getPixelArea();
822 }
823
824 void Camera::syncToCore(const CoreSyncData& data)
825 {
826 char* dataPtr = (char*)data.getBuffer();
827
828 UINT32 dirtyFlag;
829 dataPtr = rttiReadElem(dirtyFlag, dataPtr);
830 dataPtr = coreSyncReadElem((SceneActor&)*this, dataPtr);
831
832 if (dirtyFlag != (UINT32)ActorDirtyFlag::Transform)
833 dataPtr = coreSyncReadElem(*this, dataPtr);
834
835 mRecalcFrustum = true;
836 mRecalcFrustumPlanes = true;
837 mRecalcView = true;
838
839 RendererManager::instance().getActive()->notifyCameraUpdated(this, (UINT32)dirtyFlag);
840 }
841 }
842}
843