1/***********************************************************************
2    created:    Tue Mar 3 2009
3    author:     Paul D Turner (parts based on original code by Thomas Suter)
4*************************************************************************/
5/***************************************************************************
6 *   Copyright (C) 2004 - 2011 Paul D Turner & The CEGUI Development Team
7 *
8 *   Permission is hereby granted, free of charge, to any person obtaining
9 *   a copy of this software and associated documentation files (the
10 *   "Software"), to deal in the Software without restriction, including
11 *   without limitation the rights to use, copy, modify, merge, publish,
12 *   distribute, sublicense, and/or sell copies of the Software, and to
13 *   permit persons to whom the Software is furnished to do so, subject to
14 *   the following conditions:
15 *
16 *   The above copyright notice and this permission notice shall be
17 *   included in all copies or substantial portions of the Software.
18 *
19 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 *   OTHER DEALINGS IN THE SOFTWARE.
26 ***************************************************************************/
27#include "CEGUI/RendererModules/Irrlicht/RenderTarget.h"
28#include "CEGUI/GeometryBuffer.h"
29#include "CEGUI/RenderQueue.h"
30#include "CEGUI/RendererModules/Irrlicht/GeometryBuffer.h"
31
32// Start of CEGUI namespace section
33namespace CEGUI
34{
35//----------------------------------------------------------------------------//
36template <typename T>
37IrrlichtRenderTarget<T>::IrrlichtRenderTarget(IrrlichtRenderer& owner,
38                                           irr::video::IVideoDriver& driver) :
39    d_owner(owner),
40    d_driver(driver),
41    d_area(0, 0, 0, 0),
42    d_matrixValid(false),
43    d_viewDistance(0),
44#if IRRLICHT_VERSION_MAJOR > 1 || (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8)
45    d_xViewDir(1.0f)
46#else
47    d_xViewDir(driver.getDriverType() != irr::video::EDT_OPENGL ? 1.0f : -1.0f)
48#endif
49{
50}
51
52//----------------------------------------------------------------------------//
53template <typename T>
54IrrlichtRenderTarget<T>::~IrrlichtRenderTarget()
55{
56}
57
58//----------------------------------------------------------------------------//
59template <typename T>
60void IrrlichtRenderTarget<T>::draw(const GeometryBuffer& buffer)
61{
62    buffer.draw();
63}
64
65//----------------------------------------------------------------------------//
66template <typename T>
67void IrrlichtRenderTarget<T>::draw(const RenderQueue& queue)
68{
69    queue.draw();
70}
71
72//----------------------------------------------------------------------------//
73template <typename T>
74void IrrlichtRenderTarget<T>::setArea(const Rectf& area)
75{
76    d_area = area;
77    d_matrixValid = false;
78
79    RenderTargetEventArgs args(this);
80    T::fireEvent(RenderTarget::EventAreaChanged, args);
81}
82
83//----------------------------------------------------------------------------//
84template <typename T>
85const Rectf& IrrlichtRenderTarget<T>::getArea() const
86{
87    return d_area;
88}
89
90//----------------------------------------------------------------------------//
91template <typename T>
92void IrrlichtRenderTarget<T>::activate()
93{
94    irr::core::rect<irr::s32> vp(static_cast<irr::s32>(d_area.left()),
95                                 static_cast<irr::s32>(d_area.top()),
96                                 static_cast<irr::s32>(d_area.right()),
97                                 static_cast<irr::s32>(d_area.bottom()));
98    d_driver.setViewPort(vp);
99
100    if (!d_matrixValid)
101        updateMatrix();
102
103    d_driver.setTransform(irr::video::ETS_PROJECTION, d_matrix);
104    d_driver.setTransform(irr::video::ETS_VIEW, irr::core::matrix4());
105}
106
107//----------------------------------------------------------------------------//
108template <typename T>
109void IrrlichtRenderTarget<T>::deactivate()
110{
111}
112
113//----------------------------------------------------------------------------//
114template <typename T>
115void IrrlichtRenderTarget<T>::unprojectPoint(const GeometryBuffer& buff,
116                                          const Vector2f& p_in,
117                                          Vector2f& p_out) const
118{
119    if (!d_matrixValid)
120        updateMatrix();
121
122    const IrrlichtGeometryBuffer& gb =
123        static_cast<const IrrlichtGeometryBuffer&>(buff);
124
125    const irr::f32 midx = d_area.getWidth() * 0.5f;
126    const irr::f32 midy = d_area.getHeight() * 0.5f;
127
128    // viewport matrix
129    const irr::f32 vpmat_[] =
130    {
131        midx, 0, 0, 0,
132        0, -midy, 0, 0,
133        0, 0, 1, 0,
134        d_area.left() + midx, d_area.top() + midy, 0, 1
135    };
136    irr::core::matrix4 vpmat;
137    vpmat.setM(vpmat_);
138
139    // matrices used for projecting and unprojecting points
140    const irr::core::matrix4 proj(gb.getMatrix() * d_matrix * vpmat);
141    irr::core::matrix4 unproj(proj);
142    unproj.makeInverse();
143
144    irr::core::vector3df in;
145
146    // unproject the ends of the ray
147    in.X = midx;
148    in.Y = midy;
149    in.Z = -d_viewDistance;
150    irr::core::vector3df r1;
151    unproj.transformVect(r1, in);
152    in.X = p_in.d_x;
153    in.Y = p_in.d_y;
154    in.Z = 0;
155    irr::core::vector3df r2;
156    unproj.transformVect(r2, in);
157    // calculate vector of picking ray
158    const irr::core::vector3df rv(r1 - r2);
159
160    // project points to orientate them with GeometryBuffer plane
161    in.X = 0.0;
162    in.Y = 0.0;
163    irr::core::vector3df p1;
164    proj.transformVect(p1, in);
165    in.X = 1.0;
166    in.Y = 0.0;
167    irr::core::vector3df p2;
168    proj.transformVect(p2, in);
169    in.X = 0.0;
170    in.Y = 1.0;
171    irr::core::vector3df p3;
172    proj.transformVect(p3, in);
173
174    // calculate the plane normal
175    const irr::core::vector3df pn((p2 - p1).crossProduct(p3 - p1));
176    // calculate distance from origin
177    const irr::f32 plen = pn.getLength();
178    const irr::f32 dist = -(p1.X * (pn.X / plen) +
179                            p1.Y * (pn.Y / plen) +
180                            p1.Z * (pn.Z / plen));
181
182    // calculate intersection of ray and plane
183    const irr::f32 pn_dot_rv = pn.dotProduct(rv);
184    const irr::f32 tmp = pn_dot_rv != 0.0 ?
185                            (pn.dotProduct(r1) + dist) / pn_dot_rv :
186                             0.0f;
187
188    p_out.d_x = static_cast<float>(r1.X - rv.X * tmp) * d_viewDistance;
189    p_out.d_y = static_cast<float>(r1.Y - rv.Y * tmp) * d_viewDistance;
190}
191
192//----------------------------------------------------------------------------//
193template <typename T>
194void IrrlichtRenderTarget<T>::updateMatrix() const
195{
196    const float w = d_area.getWidth();
197    const float h = d_area.getHeight();
198    const float aspect = w / h;
199    const float midx = w * 0.5f;
200    const float midy = h * 0.5f;
201    d_viewDistance = midx / (aspect * 0.267949192431123f);
202
203    d_matrix.buildProjectionMatrixPerspectiveFovRH(0.523598776f, aspect,
204                                                   d_viewDistance * 0.5f,
205                                                   d_viewDistance * 2.0f);
206
207    irr::core::matrix4 tmp;
208    tmp.buildCameraLookAtMatrixRH(
209        irr::core::vector3df(d_xViewDir * midx, midy, -d_viewDistance),
210        irr::core::vector3df(d_xViewDir * midx, midy, 1),
211        irr::core::vector3df(0, -1, 0));
212
213    d_matrix *= tmp;
214
215    d_matrixValid = true;
216}
217
218//----------------------------------------------------------------------------//
219
220} // End of  CEGUI namespace section
221