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 "GUI/BsGUIViewport.h"
4#include "GUI/BsGUIWidget.h"
5#include "GUI/BsGUISkin.h"
6#include "GUI/BsGUIDimensions.h"
7#include "Components/BsCCamera.h"
8#include "RenderAPI/BsViewport.h"
9#include "RenderAPI/BsRenderTarget.h"
10#include "Error/BsException.h"
11
12namespace bs
13{
14 const String& GUIViewport::getGUITypeName()
15 {
16 static String name = "Viewport";
17 return name;
18 }
19
20 GUIViewport::GUIViewport(const String& styleName, const HCamera& camera,
21 float aspectRatio, Degree fieldOfView, const GUIDimensions& dimensions)
22 :GUIElement(styleName, dimensions), mCamera(camera), mAspectRatio(aspectRatio),
23 mFieldOfView(fieldOfView)
24 {
25 mVerticalFOV = 2.0f * Math::atan(Math::tan(mFieldOfView.valueRadians() * 0.5f) * (1.0f / mAspectRatio));
26 }
27
28 GUIViewport* GUIViewport::create(const HCamera& camera, float aspectRatio, Degree fieldOfView, const String& styleName)
29 {
30 return new (bs_alloc<GUIViewport>()) GUIViewport(getStyleName<GUIViewport>(styleName), camera, aspectRatio, fieldOfView, GUIDimensions::create());
31 }
32
33 GUIViewport* GUIViewport::create(const GUIOptions& options, const HCamera& camera,
34 float aspectRatio, Degree fieldOfView, const String& styleName)
35 {
36 return new (bs_alloc<GUIViewport>()) GUIViewport(getStyleName<GUIViewport>(styleName), camera, aspectRatio, fieldOfView, GUIDimensions::create(options));
37 }
38
39 UINT32 GUIViewport::_getNumRenderElements() const
40 {
41 return 0;
42 }
43
44 const SpriteMaterialInfo& GUIViewport::_getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const
45 {
46 BS_EXCEPT(InternalErrorException, "This element has no render element so no material can be retrieved.");
47 static SpriteMaterialInfo dummy;
48 return dummy;
49 }
50
51 void GUIViewport::_getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const
52 {
53 numVertices = 0;
54 numIndices = 0;
55 type = GUIMeshType::Triangle;
56 }
57
58 void GUIViewport::updateClippedBounds()
59 {
60 mClippedBounds = mLayoutData.area;
61 mClippedBounds.clip(mLayoutData.clipRect);
62 }
63
64 Vector2I GUIViewport::_getOptimalSize() const
65 {
66 return Vector2I(0, 0);
67 }
68
69 void GUIViewport::_fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
70 UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const
71 {
72
73 }
74
75 void GUIViewport::updateRenderElementsInternal()
76 {
77 // TODO - This doesn't get called if element mesh is dirty!!! and I need to update the viewport when offset changes (in which case mesh is marked as dirty)
78 float currentAspect = mLayoutData.area.width / (float)mLayoutData.area.height;
79 Radian currentFOV = 2.0f * Math::atan(Math::tan(mVerticalFOV * 0.5f) * currentAspect);
80
81 mCamera->setHorzFOV(currentFOV);
82
83 SPtr<Viewport> viewport = mCamera->getViewport();
84 SPtr<RenderTarget> renderTarget = viewport->getTarget();
85 const RenderTargetProperties& rtProps = renderTarget->getProperties();
86
87 float x = mLayoutData.area.x / (float)rtProps.width;
88 float y = mLayoutData.area.y / (float)rtProps.height;
89 float width = mLayoutData.area.width / (float)rtProps.width;
90 float height = mLayoutData.area.height / (float)rtProps.height;
91
92 viewport->setArea(Rect2(x, y, width, height));
93 }
94
95 void GUIViewport::_changeParentWidget(GUIWidget* widget)
96 {
97 GUIElement::_changeParentWidget(widget);
98
99 if(widget != nullptr)
100 {
101 SPtr<RenderTarget> guiRenderTarget = widget->getTarget()->getTarget();
102 SPtr<RenderTarget> cameraRenderTarget = mCamera->getViewport()->getTarget();
103
104 if(guiRenderTarget != cameraRenderTarget)
105 BS_EXCEPT(InvalidParametersException, "Camera provided to GUIViewport must use the same render target as the GUIWidget this element is located on.")
106 }
107 }
108}