Coverage Report

Created: 2026-08-29 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreLight.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
30
namespace Ogre {
31
    //-----------------------------------------------------------------------
32
0
    Light::Light() : Light(BLANKSTRING) {}
33
    //-----------------------------------------------------------------------
34
0
    Light::Light(const String& name) : MovableObject(name),
35
#ifdef OGRE_NODELESS_POSITIONING
36
        mPosition(Vector3::ZERO),
37
        mDirection(Vector3::NEGATIVE_UNIT_Z),
38
        mDerivedPosition(Vector3::ZERO),
39
        mDerivedDirection(Vector3::NEGATIVE_UNIT_Z),
40
        mDerivedCamRelativeDirty(false),
41
        mDerivedTransformDirty(false),
42
#endif
43
0
        mDiffuse(ColourValue::White),
44
0
        mSpecular(ColourValue::Black),
45
0
        mSpotOuter(Degree(40.0f)),
46
0
        mSpotInner(Degree(30.0f)),
47
0
        mSpotFalloff(2.0f),
48
0
        mSpotNearClip(0.0f),
49
0
        mAttenuation(100000.f, 1.f, 0.f, 0.f),
50
0
        mShadowFarDist(0),
51
0
        mShadowFarDistSquared(0),
52
0
        mIndexInFrame(0),
53
0
        mShadowNearClipDist(-1),
54
0
        mShadowFarClipDist(-1),
55
0
        mCameraToBeRelativeTo(0),
56
0
        mPowerScale(1.0f),
57
0
        mSourceSize(0, 0),
58
0
        mLightType(LT_POINT),
59
0
        mOwnShadowFarDist(false)
60
0
    {
61
        //mMinPixelSize should always be zero for lights otherwise lights will disapear
62
0
        mMinPixelSize = 0;
63
0
    }
64
    //-----------------------------------------------------------------------
65
    Light::~Light()
66
0
    {
67
0
    }
68
    //-----------------------------------------------------------------------
69
    void Light::setType(LightTypes type)
70
0
    {
71
0
        mLightType = type;
72
0
    }
73
    //-----------------------------------------------------------------------
74
    Light::LightTypes Light::getType(void) const
75
0
    {
76
0
        return mLightType;
77
0
    }
78
#ifdef OGRE_NODELESS_POSITIONING
79
    //-----------------------------------------------------------------------
80
    void Light::setPosition(Real x, Real y, Real z)
81
    {
82
        mPosition.x = x;
83
        mPosition.y = y;
84
        mPosition.z = z;
85
        mDerivedTransformDirty = true;
86
    }
87
    //-----------------------------------------------------------------------
88
    void Light::setPosition(const Vector3& vec)
89
    {
90
        mPosition = vec;
91
        mDerivedTransformDirty = true;
92
    }
93
    //-----------------------------------------------------------------------
94
    const Vector3& Light::getPosition(void) const
95
    {
96
        return mPosition;
97
    }
98
    //-----------------------------------------------------------------------
99
    void Light::setDirection(Real x, Real y, Real z)
100
    {
101
        mDirection.x = x;
102
        mDirection.y = y;
103
        mDirection.z = z;
104
        mDerivedTransformDirty = true;
105
    }
106
    //-----------------------------------------------------------------------
107
    void Light::setDirection(const Vector3& vec)
108
    {
109
        mDirection = vec;
110
        mDerivedTransformDirty = true;
111
    }
112
    //-----------------------------------------------------------------------
113
    const Vector3& Light::getDirection(void) const
114
    {
115
        return mDirection;
116
    }
117
#endif
118
    //-----------------------------------------------------------------------
119
    void Light::setSpotlightRange(const Radian& innerAngle, const Radian& outerAngle, Real falloff)
120
0
    {
121
0
        mSpotInner = innerAngle;
122
0
        mSpotOuter = outerAngle;
123
0
        mSpotFalloff = falloff;
124
0
    }
125
    //-----------------------------------------------------------------------
126
    void Light::setSpotlightInnerAngle(const Radian& val)
127
0
    {
128
0
        mSpotInner = val;
129
0
    }
130
    //-----------------------------------------------------------------------
131
    void Light::setSpotlightOuterAngle(const Radian& val)
132
0
    {
133
0
        mSpotOuter = val;
134
0
    }
135
    //-----------------------------------------------------------------------
136
    void Light::setSpotlightFalloff(Real val)
137
0
    {
138
0
        mSpotFalloff = val;
139
0
    }
140
    //-----------------------------------------------------------------------
141
    const Radian& Light::getSpotlightInnerAngle(void) const
142
0
    {
143
0
        return mSpotInner;
144
0
    }
145
    //-----------------------------------------------------------------------
146
    const Radian& Light::getSpotlightOuterAngle(void) const
147
0
    {
148
0
        return mSpotOuter;
149
0
    }
150
    //-----------------------------------------------------------------------
151
    Real Light::getSpotlightFalloff(void) const
152
0
    {
153
0
        return mSpotFalloff;
154
0
    }
155
    //-----------------------------------------------------------------------
156
    void Light::setDiffuseColour(float red, float green, float blue)
157
0
    {
158
0
        mDiffuse.r = red;
159
0
        mDiffuse.b = blue;
160
0
        mDiffuse.g = green;
161
0
    }
162
    //-----------------------------------------------------------------------
163
    void Light::setDiffuseColour(const ColourValue& colour)
164
0
    {
165
0
        mDiffuse = colour;
166
0
    }
167
    //-----------------------------------------------------------------------
168
    const ColourValue& Light::getDiffuseColour(void) const
169
0
    {
170
0
        return mDiffuse;
171
0
    }
172
    //-----------------------------------------------------------------------
173
    void Light::setSpecularColour(float red, float green, float blue)
174
0
    {
175
0
        mSpecular.r = red;
176
0
        mSpecular.b = blue;
177
0
        mSpecular.g = green;
178
0
    }
179
    //-----------------------------------------------------------------------
180
    void Light::setSpecularColour(const ColourValue& colour)
181
0
    {
182
0
        mSpecular = colour;
183
0
    }
184
    //-----------------------------------------------------------------------
185
    const ColourValue& Light::getSpecularColour(void) const
186
0
    {
187
0
        return mSpecular;
188
0
    }
189
    //-----------------------------------------------------------------------
190
    void Light::setPowerScale(Real power)
191
0
    {
192
0
        mPowerScale = power;
193
0
    }
194
    //-----------------------------------------------------------------------
195
    Real Light::getPowerScale(void) const
196
0
    {
197
0
        return mPowerScale;
198
0
    }
199
#ifdef OGRE_NODELESS_POSITIONING
200
    //-----------------------------------------------------------------------
201
    void Light::update(void) const
202
    {
203
        if (mDerivedTransformDirty)
204
        {
205
            if (mParentNode)
206
            {
207
                // Ok, update with SceneNode we're attached to
208
                mDerivedDirection = mParentNode->convertLocalToWorldDirection(mDirection, false);
209
                mDerivedPosition = mParentNode->convertLocalToWorldPosition(mPosition);
210
            }
211
            else
212
            {
213
                mDerivedPosition = mPosition;
214
                mDerivedDirection = mDirection;
215
            }
216
217
            mDerivedTransformDirty = false;
218
            //if the position has been updated we must update also the relative position
219
            mDerivedCamRelativeDirty = true;
220
        }
221
        if (mCameraToBeRelativeTo && mDerivedCamRelativeDirty)
222
        {
223
            mDerivedCamRelativePosition = mDerivedPosition - mCameraToBeRelativeTo->getDerivedPosition();
224
            mDerivedCamRelativeDirty = false;
225
        }
226
    }
227
    //-----------------------------------------------------------------------
228
    void Light::_notifyAttached(Node* parent, bool isTagPoint)
229
    {
230
        mDerivedTransformDirty = true;
231
232
        MovableObject::_notifyAttached(parent, isTagPoint);
233
    }
234
    //-----------------------------------------------------------------------
235
    void Light::_notifyMoved(void)
236
    {
237
        mDerivedTransformDirty = true;
238
239
        MovableObject::_notifyMoved();
240
    }
241
#endif
242
    //-----------------------------------------------------------------------
243
    const AxisAlignedBox& Light::getBoundingBox(void) const
244
0
    {
245
        // zero extent to still allow SceneQueries to work
246
0
        static AxisAlignedBox box(Vector3(0, 0, 0), Vector3(0, 0, 0));
247
0
        return box;
248
0
    }
249
    //-----------------------------------------------------------------------
250
    void Light::visitRenderables(Renderable::Visitor* visitor, 
251
        bool debugRenderables)
252
0
    {
253
        // nothing to render
254
0
    }
255
    //-----------------------------------------------------------------------
256
    const String& Light::getMovableType(void) const
257
0
    {
258
0
        return MOT_LIGHT;
259
0
    }
260
#ifdef OGRE_NODELESS_POSITIONING
261
    //-----------------------------------------------------------------------
262
    const Vector3& Light::getDerivedPosition(bool cameraRelative) const
263
    {
264
        update();
265
        if (cameraRelative && mCameraToBeRelativeTo)
266
        {
267
            return mDerivedCamRelativePosition;
268
        }
269
        else
270
        {
271
            return mDerivedPosition;
272
        }
273
    }
274
    //-----------------------------------------------------------------------
275
    const Vector3& Light::getDerivedDirection(void) const
276
    {
277
        update();
278
        return mDerivedDirection;
279
    }
280
#endif
281
    //-----------------------------------------------------------------------
282
    Vector4 Light::getAs4DVector(bool cameraRelativeIfSet) const
283
0
    {
284
0
        if (mLightType == Light::LT_DIRECTIONAL)
285
0
        {
286
0
            return Vector4(-getDerivedDirection(), // negate direction as 'position'
287
0
                           0.0);                   // infinite distance
288
0
        }   
289
0
        else
290
0
        {
291
0
            return Vector4(getDerivedPosition(cameraRelativeIfSet), 1.0);
292
0
        }
293
0
    }
294
    Vector3f Light::getDerivedSourceHalfWidth() const
295
0
    {
296
0
        auto& ori = mParentNode->_getDerivedOrientation();
297
0
        auto& scale = mParentNode->_getDerivedScale();
298
0
        return Vector3f(ori.xAxis()) * mSourceSize[0] * scale[0] * 0.5f;
299
0
    }
300
    Vector3f Light::getDerivedSourceHalfHeight() const
301
0
    {
302
0
        auto& ori = mParentNode->_getDerivedOrientation();
303
0
        auto& scale = mParentNode->_getDerivedScale();
304
0
        return Vector3f(ori.yAxis()) * mSourceSize[1] * scale[1] * 0.5f;
305
0
    }
306
    //-----------------------------------------------------------------------
307
    const PlaneBoundedVolume& Light::_getNearClipVolume(const Camera* const cam) const
308
0
    {
309
        // First check if the light is close to the near plane, since
310
        // in this case we have to build a degenerate clip volume
311
0
        mNearClipVolume.planes.clear();
312
0
        mNearClipVolume.outside = Plane::NEGATIVE_SIDE;
313
314
0
        Real n = cam->getNearClipDistance();
315
        // Homogenous position
316
0
        Vector4 lightPos = getAs4DVector();
317
        // 3D version (not the same as _getDerivedPosition, is -direction for
318
        // directional lights)
319
0
        Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
320
321
        // Get eye-space light position
322
        // use 4D vector so directional lights still work
323
0
        Vector4 eyeSpaceLight = cam->getViewMatrix() * lightPos;
324
        // Find distance to light, project onto -Z axis
325
0
        Real d = eyeSpaceLight.dotProduct(
326
0
            Vector4(0, 0, -1, -n) );
327
0
        #define THRESHOLD 1e-6
328
0
        if (d > THRESHOLD || d < -THRESHOLD)
329
0
        {
330
            // light is not too close to the near plane
331
            // First find the worldspace positions of the corners of the viewport
332
0
            const Vector3 *corner = cam->getWorldSpaceCorners();
333
0
            int winding = (d < 0) ^ cam->isReflected() ? +1 : -1;
334
            // Iterate over world points and form side planes
335
0
            Vector3 normal;
336
0
            Vector3 lightDir;
337
0
            for (unsigned int i = 0; i < 4; ++i)
338
0
            {
339
                // Figure out light dir
340
0
                lightDir = lightPos3 - (corner[i] * lightPos.w);
341
                // Cross with anticlockwise corner, therefore normal points in
342
0
                normal = (corner[i] - corner[(i+winding)%4])
343
0
                    .crossProduct(lightDir);
344
0
                normal.normalise();
345
0
                mNearClipVolume.planes.push_back(Plane(normal, corner[i]));
346
0
            }
347
348
            // Now do the near plane plane
349
0
            normal = cam->getFrustumPlane(FRUSTUM_PLANE_NEAR).normal;
350
0
            if (d < 0)
351
0
            {
352
                // Behind near plane
353
0
                normal = -normal;
354
0
            }
355
0
            const Vector3& cameraPos = cam->getDerivedPosition();
356
0
            mNearClipVolume.planes.push_back(Plane(normal, cameraPos));
357
358
            // Finally, for a point/spot light we can add a sixth plane
359
            // This prevents false positives from behind the light
360
0
            if (mLightType != LT_DIRECTIONAL)
361
0
            {
362
                // Direction from light perpendicular to near plane
363
0
                mNearClipVolume.planes.push_back(Plane(-normal, lightPos3));
364
0
            }
365
0
        }
366
0
        else
367
0
        {
368
            // light is close to being on the near plane
369
            // degenerate volume including the entire scene 
370
            // we will always require light / dark caps
371
0
            mNearClipVolume.planes.push_back(Plane(Vector3::UNIT_Z, -n));
372
0
            mNearClipVolume.planes.push_back(Plane(-Vector3::UNIT_Z, n));
373
0
        }
374
375
0
        return mNearClipVolume;
376
0
    }
377
    //-----------------------------------------------------------------------
378
    const PlaneBoundedVolumeList& Light::_getFrustumClipVolumes(const Camera* const cam) const
379
0
    {
380
381
        // Homogenous light position
382
0
        Vector4 lightPos = getAs4DVector();
383
        // 3D version (not the same as _getDerivedPosition, is -direction for
384
        // directional lights)
385
0
        Vector3 lightPos3 = Vector3(lightPos.x, lightPos.y, lightPos.z);
386
387
0
        const Vector3 *clockwiseVerts[4];
388
389
        // Get worldspace frustum corners
390
0
        const Vector3* corners = cam->getWorldSpaceCorners();
391
0
        int windingPt0 = cam->isReflected() ? 1 : 0;
392
0
        int windingPt1 = cam->isReflected() ? 0 : 1;
393
394
0
        bool infiniteViewDistance = (cam->getFarClipDistance() == 0);
395
396
0
        Vector3 notSoFarCorners[4];
397
0
        if(infiniteViewDistance)
398
0
        {
399
0
            Vector3 camPosition = cam->getRealPosition();
400
0
            notSoFarCorners[0] = corners[0] + corners[0] - camPosition;
401
0
            notSoFarCorners[1] = corners[1] + corners[1] - camPosition;
402
0
            notSoFarCorners[2] = corners[2] + corners[2] - camPosition;
403
0
            notSoFarCorners[3] = corners[3] + corners[3] - camPosition;
404
0
        }
405
406
0
        mFrustumClipVolumes.clear();
407
0
        for (unsigned short n = 0; n < 6; ++n)
408
0
        {
409
            // Skip far plane if infinite view frustum
410
0
            if (infiniteViewDistance && n == FRUSTUM_PLANE_FAR)
411
0
                continue;
412
413
0
            const Plane& plane = cam->getFrustumPlane(n);
414
0
            Vector4 planeVec(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
415
            // planes face inwards, we need to know if light is on negative side
416
0
            Real d = planeVec.dotProduct(lightPos);
417
0
            if (d < -1e-06)
418
0
            {
419
                // Ok, this is a valid one
420
                // clockwise verts mean we can cross-product and always get normals
421
                // facing into the volume we create
422
423
0
                mFrustumClipVolumes.push_back(PlaneBoundedVolume());
424
0
                PlaneBoundedVolume& vol = mFrustumClipVolumes.back();
425
0
                switch(n)
426
0
                {
427
0
                case(FRUSTUM_PLANE_NEAR):
428
0
                    clockwiseVerts[0] = corners + 3;
429
0
                    clockwiseVerts[1] = corners + 2;
430
0
                    clockwiseVerts[2] = corners + 1;
431
0
                    clockwiseVerts[3] = corners + 0;
432
0
                    break;
433
0
                case(FRUSTUM_PLANE_FAR):
434
0
                    clockwiseVerts[0] = corners + 7;
435
0
                    clockwiseVerts[1] = corners + 6;
436
0
                    clockwiseVerts[2] = corners + 5;
437
0
                    clockwiseVerts[3] = corners + 4;
438
0
                    break;
439
0
                case(FRUSTUM_PLANE_LEFT):
440
0
                    clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 1 : corners + 5;
441
0
                    clockwiseVerts[1] = corners + 1;
442
0
                    clockwiseVerts[2] = corners + 2;
443
0
                    clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 2 : corners + 6;
444
0
                    break;
445
0
                case(FRUSTUM_PLANE_RIGHT):
446
0
                    clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 3 : corners + 7;
447
0
                    clockwiseVerts[1] = corners + 3;
448
0
                    clockwiseVerts[2] = corners + 0;
449
0
                    clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 0 : corners + 4;
450
0
                    break;
451
0
                case(FRUSTUM_PLANE_TOP):
452
0
                    clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 0 : corners + 4;
453
0
                    clockwiseVerts[1] = corners + 0;
454
0
                    clockwiseVerts[2] = corners + 1;
455
0
                    clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 1 : corners + 5;
456
0
                    break;
457
0
                case(FRUSTUM_PLANE_BOTTOM):
458
0
                    clockwiseVerts[0] = infiniteViewDistance ? notSoFarCorners + 2 : corners + 6;
459
0
                    clockwiseVerts[1] = corners + 2;
460
0
                    clockwiseVerts[2] = corners + 3;
461
0
                    clockwiseVerts[3] = infiniteViewDistance ? notSoFarCorners + 3 : corners + 7;
462
0
                    break;
463
0
                };
464
465
                // Build a volume
466
                // Iterate over world points and form side planes
467
0
                Vector3 normal;
468
0
                Vector3 lightDir;
469
0
                unsigned int infiniteViewDistanceInt = infiniteViewDistance ? 1 : 0;
470
0
                for (unsigned int i = 0; i < 4 - infiniteViewDistanceInt; ++i)
471
0
                {
472
                    // Figure out light dir
473
0
                    lightDir = lightPos3 - (*(clockwiseVerts[i]) * lightPos.w);
474
0
                    Vector3 edgeDir = *(clockwiseVerts[(i+windingPt1)%4]) - *(clockwiseVerts[(i+windingPt0)%4]);
475
                    // Cross with anticlockwise corner, therefore normal points in
476
0
                    normal = edgeDir.crossProduct(lightDir);
477
0
                    normal.normalise();
478
0
                    vol.planes.push_back(Plane(normal, *(clockwiseVerts[i])));
479
0
                }
480
481
                // Now do the near plane (this is the plane of the side we're 
482
                // talking about, with the normal inverted (d is already interpreted as -ve)
483
0
                vol.planes.push_back( Plane(-plane.normal, plane.d) );
484
485
                // Finally, for a point/spot light we can add a sixth plane
486
                // This prevents false positives from behind the light
487
0
                if (mLightType != LT_DIRECTIONAL)
488
0
                {
489
                    // re-use our own plane normal
490
0
                    vol.planes.push_back(Plane(plane.normal, lightPos3));
491
0
                }
492
0
            }
493
0
        }
494
495
0
        return mFrustumClipVolumes;
496
0
    }
497
    //-----------------------------------------------------------------------
498
    uint32 Light::getTypeFlags(void) const
499
0
    {
500
0
        return SceneManager::LIGHT_TYPE_MASK;
501
0
    }
502
    //---------------------------------------------------------------------
503
    void Light::_calcTempSquareDist(const Vector3& worldPos)
504
0
    {
505
0
        if (mLightType == LT_DIRECTIONAL)
506
0
        {
507
            // make sure directional lights are always in front
508
            // even of point lights at worldPos
509
            // tempSquareDist is just a tag for sorting, and nobody will take the sqrt
510
0
            tempSquareDist = -1;
511
0
        }
512
0
        else
513
0
        {
514
0
            tempSquareDist = 
515
0
                (worldPos - getDerivedPosition()).squaredLength();
516
0
        }
517
518
0
    }
519
    //-----------------------------------------------------------------------
520
    class LightDiffuseColourValue : public AnimableValue
521
    {
522
    protected:
523
        Light* mLight;
524
    public:
525
0
        LightDiffuseColourValue(Light* l) :AnimableValue(COLOUR) 
526
0
        { mLight = l; }
527
        void setValue(const ColourValue& val) override
528
0
        {
529
0
            mLight->setDiffuseColour(val);
530
0
        }
531
        void applyDeltaValue(const ColourValue& val) override
532
0
        {
533
0
            setValue(mLight->getDiffuseColour() + val);
534
0
        }
535
        void setCurrentStateAsBaseValue(void) override
536
0
        {
537
0
            setAsBaseValue(mLight->getDiffuseColour());
538
0
        }
539
540
    };
541
    //-----------------------------------------------------------------------
542
    class LightSpecularColourValue : public AnimableValue
543
    {
544
    protected:
545
        Light* mLight;
546
    public:
547
0
        LightSpecularColourValue(Light* l) :AnimableValue(COLOUR) 
548
0
        { mLight = l; }
549
        void setValue(const ColourValue& val) override
550
0
        {
551
0
            mLight->setSpecularColour(val);
552
0
        }
553
        void applyDeltaValue(const ColourValue& val) override
554
0
        {
555
0
            setValue(mLight->getSpecularColour() + val);
556
0
        }
557
        void setCurrentStateAsBaseValue(void) override
558
0
        {
559
0
            setAsBaseValue(mLight->getSpecularColour());
560
0
        }
561
562
    };
563
    //-----------------------------------------------------------------------
564
    class LightAttenuationValue : public AnimableValue
565
    {
566
    protected:
567
        Light* mLight;
568
    public:
569
0
        LightAttenuationValue(Light* l) :AnimableValue(VECTOR4) 
570
0
        { mLight = l; }
571
        void setValue(const Vector4& val) override
572
0
        {
573
0
            mLight->setAttenuation(val.x, val.y, val.z, val.w);
574
0
        }
575
        void applyDeltaValue(const Vector4& val) override
576
0
        {
577
0
            const auto& attenuation = mLight->getAttenuation();
578
0
            setValue(Vector4(attenuation[0], attenuation[1], attenuation[2], attenuation[3]) + val);
579
0
        }
580
        void setCurrentStateAsBaseValue(void) override
581
0
        {
582
0
            setAsBaseValue(mLight->getAttenuation());
583
0
        }
584
585
    };
586
    //-----------------------------------------------------------------------
587
    class LightSpotlightInnerValue : public AnimableValue
588
    {
589
    protected:
590
        Light* mLight;
591
    public:
592
0
        LightSpotlightInnerValue(Light* l) : AnimableValue(RADIAN), mLight(l) {}
593
        void setValue(const Radian& val) override
594
0
        {
595
0
            mLight->setSpotlightInnerAngle(val);
596
0
        }
597
        void applyDeltaValue(const Radian& val) override
598
0
        {
599
0
            setValue(mLight->getSpotlightInnerAngle() + val);
600
0
        }
601
        void setCurrentStateAsBaseValue(void) override
602
0
        {
603
0
            setAsBaseValue(mLight->getSpotlightInnerAngle());
604
0
        }
605
606
    };
607
    //-----------------------------------------------------------------------
608
    class LightSpotlightOuterValue : public AnimableValue
609
    {
610
    protected:
611
        Light* mLight;
612
    public:
613
0
        LightSpotlightOuterValue(Light* l) : AnimableValue(RADIAN), mLight(l) {}
614
        void setValue(const Radian& val) override
615
0
        {
616
0
            mLight->setSpotlightOuterAngle(val);
617
0
        }
618
        void applyDeltaValue(const Radian& val) override
619
0
        {
620
0
            setValue(mLight->getSpotlightOuterAngle() + val);
621
0
        }
622
        void setCurrentStateAsBaseValue(void) override
623
0
        {
624
0
            setAsBaseValue(mLight->getSpotlightOuterAngle());
625
0
        }
626
627
    };
628
    //-----------------------------------------------------------------------
629
    class LightSpotlightFalloffValue : public AnimableValue
630
    {
631
    protected:
632
        Light* mLight;
633
    public:
634
0
        LightSpotlightFalloffValue(Light* l) :AnimableValue(REAL) 
635
0
        { mLight = l; }
636
        void setValue(Real val) override
637
0
        {
638
0
            mLight->setSpotlightFalloff(val);
639
0
        }
640
        void applyDeltaValue(Real val) override
641
0
        {
642
0
            setValue(mLight->getSpotlightFalloff() + val);
643
0
        }
644
        void setCurrentStateAsBaseValue(void) override
645
0
        {
646
0
            setAsBaseValue(mLight->getSpotlightFalloff());
647
0
        }
648
649
    };
650
    //-----------------------------------------------------------------------
651
    AnimableValuePtr Light::createAnimableValue(const String& valueName)
652
0
    {
653
0
        if (valueName == "diffuseColour")
654
0
        {
655
0
            return AnimableValuePtr(
656
0
                OGRE_NEW LightDiffuseColourValue(this));
657
0
        }
658
0
        else if(valueName == "specularColour")
659
0
        {
660
0
            return AnimableValuePtr(
661
0
                OGRE_NEW LightSpecularColourValue(this));
662
0
        }
663
0
        else if (valueName == "attenuation")
664
0
        {
665
0
            return AnimableValuePtr(
666
0
                OGRE_NEW LightAttenuationValue(this));
667
0
        }
668
0
        else if (valueName == "spotlightInner")
669
0
        {
670
0
            return AnimableValuePtr(
671
0
                OGRE_NEW LightSpotlightInnerValue(this));
672
0
        }
673
0
        else if (valueName == "spotlightOuter")
674
0
        {
675
0
            return AnimableValuePtr(
676
0
                OGRE_NEW LightSpotlightOuterValue(this));
677
0
        }
678
0
        else if (valueName == "spotlightFalloff")
679
0
        {
680
0
            return AnimableValuePtr(
681
0
                OGRE_NEW LightSpotlightFalloffValue(this));
682
0
        }
683
0
        else
684
0
        {
685
0
            return MovableObject::createAnimableValue(valueName);
686
0
        }
687
0
    }
688
    //-----------------------------------------------------------------------
689
    void Light::setCustomShadowCameraSetup(const ShadowCameraSetupPtr& customShadowSetup)
690
0
    {
691
0
        mCustomShadowCameraSetup = customShadowSetup;
692
0
    }
693
    //-----------------------------------------------------------------------
694
    void Light::resetCustomShadowCameraSetup()
695
0
    {
696
0
        mCustomShadowCameraSetup.reset();
697
0
    }
698
    //-----------------------------------------------------------------------
699
    const ShadowCameraSetupPtr& Light::getCustomShadowCameraSetup() const
700
0
    {
701
0
        return mCustomShadowCameraSetup;
702
0
    }
703
    //-----------------------------------------------------------------------
704
    void Light::setShadowFarDistance(Real distance)
705
0
    {
706
0
        mOwnShadowFarDist = true;
707
0
        mShadowFarDist = distance;
708
0
        mShadowFarDistSquared = distance * distance;
709
0
    }
710
    //-----------------------------------------------------------------------
711
    void Light::resetShadowFarDistance(void)
712
0
    {
713
0
        mOwnShadowFarDist = false;
714
0
    }
715
    //-----------------------------------------------------------------------
716
    Real Light::getShadowFarDistance(void) const
717
0
    {
718
0
        if (mOwnShadowFarDist)
719
0
            return mShadowFarDist;
720
0
        else
721
0
            return mManager->getShadowFarDistance ();
722
0
    }
723
    //-----------------------------------------------------------------------
724
    Real Light::getShadowFarDistanceSquared(void) const
725
0
    {
726
0
        if (mOwnShadowFarDist)
727
0
            return mShadowFarDistSquared;
728
0
        else
729
0
            return mManager->getShadowFarDistanceSquared ();
730
0
    }
731
    //---------------------------------------------------------------------
732
    void Light::_setCameraRelative(Camera* cam)
733
0
    {
734
0
        mCameraToBeRelativeTo = cam;
735
#ifdef OGRE_NODELESS_POSITIONING
736
        mDerivedCamRelativeDirty = true;
737
#endif
738
0
    }
739
    //---------------------------------------------------------------------
740
    Real Light::_deriveShadowNearClipDistance(const Camera* maincam) const
741
0
    {
742
0
        if (mShadowNearClipDist > 0)
743
0
            return mShadowNearClipDist;
744
0
        else
745
0
            return maincam->getNearClipDistance();
746
0
    }
747
    //---------------------------------------------------------------------
748
    Real Light::_deriveShadowFarClipDistance() const
749
0
    {
750
0
        if (mShadowFarClipDist >= 0)
751
0
            return mShadowFarClipDist;
752
0
        else
753
0
        {
754
0
            if (mLightType == LT_DIRECTIONAL)
755
0
                return 0;
756
0
            else
757
0
                return mAttenuation[0];
758
0
        }
759
0
    }
760
    //-----------------------------------------------------------------------
761
    void Light::setCustomParameter(uint16 index, const Ogre::Vector4f &value)
762
0
    {
763
0
        mCustomParameters[index] = value;
764
0
    }
765
    //-----------------------------------------------------------------------
766
    const Vector4f &Light::getCustomParameter(uint16 index) const
767
0
    {
768
0
        CustomParameterMap::const_iterator i = mCustomParameters.find(index);
769
0
        if (i != mCustomParameters.end())
770
0
        {
771
0
            return i->second;
772
0
        }
773
0
        else
774
0
        {
775
0
            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
776
0
                "Parameter at the given index was not found.",
777
0
                "Light::getCustomParameter");
778
0
        }
779
0
    }
780
    //-----------------------------------------------------------------------
781
    void Light::_updateCustomGpuParameter(uint16 paramIndex, const GpuProgramParameters::AutoConstantEntry& constantEntry, GpuProgramParameters *params) const
782
0
    {
783
0
        CustomParameterMap::const_iterator i = mCustomParameters.find(paramIndex);
784
0
        if (i != mCustomParameters.end())
785
0
        {
786
0
            params->_writeRawConstant(constantEntry.physicalIndex, i->second, 
787
0
                constantEntry.elementCount);
788
0
        }
789
0
    }
790
    //-----------------------------------------------------------------------
791
    bool Light::isInLightRange(const Ogre::Sphere& container) const
792
0
    {
793
0
        bool isIntersect = true;
794
        //directional light always intersects (check only spotlight and point)
795
0
        if (mLightType != LT_DIRECTIONAL)
796
0
        {
797
0
#ifndef OGRE_NODELESS_POSITIONING
798
0
            const auto& mDerivedDirection = getDerivedDirection();
799
0
            const auto& mDerivedPosition = mParentNode->_getDerivedPosition();
800
0
#endif
801
            //Check that the sphere is within the sphere of the light
802
0
            isIntersect = container.intersects(Sphere(mDerivedPosition, mAttenuation[0]));
803
            //If this is a spotlight, check that the sphere is within the cone of the spot light
804
0
            if ((isIntersect) && (mLightType == LT_SPOTLIGHT))
805
0
            {
806
                //check first check of the sphere surrounds the position of the light
807
                //(this covers the case where the center of the sphere is behind the position of the light
808
                // something which is not covered in the next test).
809
0
                isIntersect = container.intersects(mDerivedPosition);
810
                //if not test cones
811
0
                if (!isIntersect)
812
0
                {
813
                    //Calculate the cone that exists between the sphere and the center position of the light
814
0
                    Ogre::Vector3 lightSphereConeDirection = container.getCenter() - mDerivedPosition;
815
0
                    Ogre::Radian halfLightSphereConeAngle = Math::ASin(container.getRadius() / lightSphereConeDirection.length());
816
817
                    //Check that the light cone and the light-position-to-sphere cone intersect)
818
0
                    Radian angleBetweenConeDirections = lightSphereConeDirection.angleBetween(mDerivedDirection);
819
0
                    isIntersect = angleBetweenConeDirections <=  halfLightSphereConeAngle + mSpotOuter * 0.5;
820
0
                }
821
0
            }
822
0
        }
823
0
        return isIntersect;
824
0
    }
825
826
    //-----------------------------------------------------------------------
827
    bool Light::isInLightRange(const Ogre::AxisAlignedBox& container) const
828
0
    {
829
0
#ifndef OGRE_NODELESS_POSITIONING
830
0
        const auto& mDerivedDirection = getDerivedDirection();
831
0
        const auto& mDerivedPosition = mParentNode->_getDerivedPosition();
832
0
#endif
833
0
        bool isIntersect = true;
834
        //Check the 2 simple / obvious situations. Light is directional or light source is inside the container
835
0
        if ((mLightType != LT_DIRECTIONAL) && (container.intersects(mDerivedPosition) == false))
836
0
        {
837
0
            float range = mAttenuation[0];
838
            //Check that the container is within the sphere of the light
839
0
            isIntersect = Math::intersects(Sphere(mDerivedPosition, range),container);
840
            //If this is a spotlight, do a more specific check
841
0
            if ((isIntersect) && (mLightType == LT_SPOTLIGHT) && (mSpotOuter.valueRadians() <= Math::PI))
842
0
            {
843
                //Create a rough bounding box around the light and check if
844
0
                Quaternion localToWorld = Vector3::NEGATIVE_UNIT_Z.getRotationTo(mDerivedDirection);
845
846
0
                Real boxOffset = Math::Sin(mSpotOuter * 0.5) * range;
847
0
                AxisAlignedBox lightBoxBound;
848
0
                lightBoxBound.merge(Vector3::ZERO);
849
0
                lightBoxBound.merge(localToWorld * Vector3(boxOffset, boxOffset, -range));
850
0
                lightBoxBound.merge(localToWorld * Vector3(-boxOffset, boxOffset, -range));
851
0
                lightBoxBound.merge(localToWorld * Vector3(-boxOffset, -boxOffset, -range));
852
0
                lightBoxBound.merge(localToWorld * Vector3(boxOffset, -boxOffset, -range));
853
0
                lightBoxBound.setMaximum(lightBoxBound.getMaximum() + mDerivedPosition);
854
0
                lightBoxBound.setMinimum(lightBoxBound.getMinimum() + mDerivedPosition);
855
0
                isIntersect = lightBoxBound.intersects(container);
856
                
857
                //If the bounding box check succeeded do one more test
858
0
                if (isIntersect)
859
0
                {
860
                    //Check intersection again with the bounding sphere of the container
861
                    //Helpful for when the light is at an angle near one of the vertexes of the bounding box
862
0
                    isIntersect = isInLightRange(Sphere(container.getCenter(), 
863
0
                        container.getHalfSize().length()));
864
0
                }
865
0
            }
866
0
        }
867
0
        return isIntersect;
868
0
    }
869
    //-----------------------------------------------------------------------
870
    //-----------------------------------------------------------------------
871
    const String MOT_LIGHT = "Light";
872
    //-----------------------------------------------------------------------
873
    const String& LightFactory::getType(void) const
874
0
    {
875
0
        return MOT_LIGHT;
876
0
    }
877
    //-----------------------------------------------------------------------
878
    MovableObject* LightFactory::createInstanceImpl( const String& name, 
879
        const NameValuePairList* params)
880
0
    {
881
882
0
        Light* light = OGRE_NEW Light(name);
883
 
884
0
        if(params)
885
0
        {
886
0
            NameValuePairList::const_iterator ni;
887
888
            // Setting the light type first before any property specific to a certain light type
889
0
            if ((ni = params->find("type")) != params->end())
890
0
            {
891
0
                if (ni->second == "point")
892
0
                    light->setType(Light::LT_POINT);
893
0
                else if (ni->second == "directional")
894
0
                    light->setType(Light::LT_DIRECTIONAL);
895
0
                else if (ni->second == "spotlight")
896
0
                    light->setType(Light::LT_SPOTLIGHT);
897
0
                else
898
0
                    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
899
0
                        "Invalid light type '" + ni->second + "'.",
900
0
                        "LightFactory::createInstance");
901
0
            }
902
903
            // Common properties
904
            //if ((ni = params->find("position")) != params->end())
905
            //    light->setPosition(StringConverter::parseVector3(ni->second));
906
907
            //if ((ni = params->find("direction")) != params->end())
908
            //    light->setDirection(StringConverter::parseVector3(ni->second));
909
910
0
            if ((ni = params->find("diffuseColour")) != params->end())
911
0
                light->setDiffuseColour(StringConverter::parseColourValue(ni->second));
912
913
0
            if ((ni = params->find("specularColour")) != params->end())
914
0
                light->setSpecularColour(StringConverter::parseColourValue(ni->second));
915
916
0
            if ((ni = params->find("attenuation")) != params->end())
917
0
            {
918
0
                Vector4 attenuation = StringConverter::parseVector4(ni->second);
919
0
                light->setAttenuation(attenuation.x, attenuation.y, attenuation.z, attenuation.w);
920
0
            }
921
922
0
            if ((ni = params->find("castShadows")) != params->end())
923
0
                light->setCastShadows(StringConverter::parseBool(ni->second));
924
925
0
            if ((ni = params->find("visible")) != params->end())
926
0
                light->setVisible(StringConverter::parseBool(ni->second));
927
928
0
            if ((ni = params->find("powerScale")) != params->end())
929
0
                light->setPowerScale(StringConverter::parseReal(ni->second));
930
931
0
            if ((ni = params->find("shadowFarDistance")) != params->end())
932
0
                light->setShadowFarDistance(StringConverter::parseReal(ni->second));
933
934
935
            // Spotlight properties
936
0
            if ((ni = params->find("spotlightInner")) != params->end())
937
0
                light->setSpotlightInnerAngle(StringConverter::parseAngle(ni->second));
938
939
0
            if ((ni = params->find("spotlightOuter")) != params->end())
940
0
                light->setSpotlightOuterAngle(StringConverter::parseAngle(ni->second));
941
942
0
            if ((ni = params->find("spotlightFalloff")) != params->end())
943
0
                light->setSpotlightFalloff(StringConverter::parseReal(ni->second));
944
0
        }
945
946
0
        return light;
947
0
    }
948
} // Namespace