Torque3D Documentation / _generateds / lightFlareData.cpp

lightFlareData.cpp

Engine/source/T3D/lightFlareData.cpp

More...

Public Functions

ConsoleDocClass(LightFlareData , "@brief Defines <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> light flare effect usable by scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lights.\n\n</a>" "%<a href="/coding/class/classlightflaredata/">LightFlareData</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> datablock which defines <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> type of flare effect. " "This may then be referenced by other classes which support the rendering " "of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> flare: Sun, <a href="/coding/class/classscattersky/">ScatterSky</a> , <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">LightBase.\n\n</a>" "A flare contains one or more elements defined in the element *named fields " "of % LightFlareData, with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> maximum of ten elements. Each element is rendered " "as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 2D sprite in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">screenspace.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//example from Full Template, core/art/datablocks/lights." TORQUE_SCRIPT_EXTENSION "\n" "datablock <a href="/coding/class/classlightflaredata/">LightFlareData</a>(LightFlareExample0)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " overallScale=2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " flareEnabled=true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " renderReflectPass=true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " flareTexture=\"./../special/lensFlareSheet1\";\n" "   occlusionRadius = 0.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRect[0] = \"0 512 512 512\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementDist[0] = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementScale[0] = 0.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementTint[0] = \"1.0 1.0 1.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRotate[0] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementUseLightColor[0] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRect[1] = \"512 0 512 512\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementDist[1] = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementScale[1] = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementTint[1] = \"0.5 0.5 0.5\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRotate[1] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementUseLightColor[1] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "The elementDist field defines where along the flare's beam the element appears. " "A distance of 0.0 is directly over the light source, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> distance of 1.0 " "is at the screen center, and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> distance of 2.0 is at the position of the " "light <a href="/coding/file/pointer_8h/#pointer_8h_1adb82dfe18535e9a30aa97d275f82bd55">source</a> mirrored across the screen <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">center.\n</a>" " @image html images/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lightFlareData_diagram.png\n</a>" " @ingroup Lighting" )
DefineEngineMethod(LightFlareData , apply , void , () , "Intended as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> helper <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> developers and editor <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scripts.\n</a>" "Force trigger an inspectPostApply" )

Detailed Description

Public Functions

ConsoleDocClass(LightFlareData , "@brief Defines <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> light flare effect usable by scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lights.\n\n</a>" "%<a href="/coding/class/classlightflaredata/">LightFlareData</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> datablock which defines <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> type of flare effect. " "This may then be referenced by other classes which support the rendering " "of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> flare: Sun, <a href="/coding/class/classscattersky/">ScatterSky</a> , <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">LightBase.\n\n</a>" "A flare contains one or more elements defined in the element *named fields " "of % LightFlareData, with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> maximum of ten elements. Each element is rendered " "as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> 2D sprite in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">screenspace.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//example from Full Template, core/art/datablocks/lights." TORQUE_SCRIPT_EXTENSION "\n" "datablock <a href="/coding/class/classlightflaredata/">LightFlareData</a>(LightFlareExample0)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " overallScale=2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " flareEnabled=true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " renderReflectPass=true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " flareTexture=\"./../special/lensFlareSheet1\";\n" "   occlusionRadius = 0.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRect[0] = \"0 512 512 512\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementDist[0] = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementScale[0] = 0.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementTint[0] = \"1.0 1.0 1.0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRotate[0] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementUseLightColor[0] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   \<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRect[1] = \"512 0 512 512\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementDist[1] = 0.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementScale[1] = 2.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementTint[1] = \"0.5 0.5 0.5\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementRotate[1] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elementUseLightColor[1] = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n</a>" "The elementDist field defines where along the flare's beam the element appears. " "A distance of 0.0 is directly over the light source, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> distance of 1.0 " "is at the screen center, and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> distance of 2.0 is at the position of the " "light <a href="/coding/file/pointer_8h/#pointer_8h_1adb82dfe18535e9a30aa97d275f82bd55">source</a> mirrored across the screen <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">center.\n</a>" " @image html images/<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lightFlareData_diagram.png\n</a>" " @ingroup Lighting" )

DefineEngineMethod(LightFlareData , apply , void , () , "Intended as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> helper <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> developers and editor <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scripts.\n</a>" "Force trigger an inspectPostApply" )

IMPLEMENT_CO_DATABLOCK_V1(LightFlareData )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "T3D/lightFlareData.h"
 26
 27#include "core/stream/bitStream.h"
 28#include "console/engineAPI.h"
 29#include "lighting/lightInfo.h"
 30#include "lighting/lightQuery.h"
 31#include "math/mathUtils.h"
 32#include "math/mathIO.h"
 33#include "scene/sceneRenderState.h"
 34#include "gfx/gfxOcclusionQuery.h"
 35#include "gfx/gfxDrawUtil.h"
 36#include "gfx/gfxTextureManager.h"
 37#include "gfx/sim/debugDraw.h"
 38#include "renderInstance/renderPassManager.h"
 39#include "T3D/gameBase/gameConnection.h"
 40#include "T3D/gameBase/processList.h"
 41#include "collision/collision.h"
 42#include "lighting/lightManager.h"
 43
 44const U32 LightFlareData::LosMask = STATIC_COLLISION_TYPEMASK |
 45                                    ShapeBaseObjectType |
 46                                    StaticShapeObjectType |
 47                                    ItemObjectType;
 48
 49
 50LightFlareState::~LightFlareState()
 51{
 52}
 53
 54void LightFlareState::clear()
 55{
 56   visChangedTime = 0;
 57   visible = false;
 58   scale = 1.0f;
 59   fullBrightness = 1.0f;
 60   lightMat = MatrixF::Identity;
 61   lightInfo = NULL;
 62   worldRadius = -1.0f;
 63   occlusion = -1.0f;
 64}
 65
 66Point3F LightFlareData::sBasePoints[] =
 67{ 
 68   Point3F( -0.5, 0.5, 0.0 ), 
 69   Point3F( -0.5, -0.5, 0.0 ),   
 70   Point3F( 0.5, -0.5, 0.0 ),  
 71   Point3F( 0.5, 0.5, 0.0 ) 
 72};
 73
 74
 75IMPLEMENT_CO_DATABLOCK_V1( LightFlareData );
 76
 77ConsoleDocClass( LightFlareData,
 78   "@brief Defines a light flare effect usable by scene lights.\n\n"      
 79   
 80   "%LightFlareData is a datablock which defines a type of flare effect. "
 81   "This may then be referenced by other classes which support the rendering "
 82   "of a flare: Sun, ScatterSky, LightBase.\n\n"
 83   
 84   "A flare contains one or more elements defined in the element* named fields "
 85   "of %LightFlareData, with a maximum of ten elements. Each element is rendered "
 86   "as a 2D sprite in screenspace.\n\n"
 87
 88   "@tsexample\n"
 89   "// example from Full Template, core/art/datablocks/lights." TORQUE_SCRIPT_EXTENSION "\n"
 90   "datablock LightFlareData( LightFlareExample0 )\n"
 91   "{\n"
 92   "   overallScale = 2.0;\n"
 93   "   flareEnabled = true;\n"
 94   "   renderReflectPass = true;\n"
 95   "   flareTexture = \"./../special/lensFlareSheet1\";\n"
 96   "   occlusionRadius = 0.25;\n"
 97   "   \n"
 98   "   elementRect[0] = \"0 512 512 512\";\n"
 99   "   elementDist[0] = 0.0;\n"
100   "   elementScale[0] = 0.5;\n"
101   "   elementTint[0] = \"1.0 1.0 1.0\";\n"
102   "   elementRotate[0] = false;\n"
103   "   elementUseLightColor[0] = false;\n"
104   "   \n"
105   "   elementRect[1] = \"512 0 512 512\";\n"
106   "   elementDist[1] = 0.0;\n"
107   "   elementScale[1] = 2.0;\n"
108   "   elementTint[1] = \"0.5 0.5 0.5\";\n"
109   "   elementRotate[1] = false;\n"
110   "   elementUseLightColor[1] = false;\n"
111   "};\n"
112   "@endtsexample\n"
113   "The elementDist field defines where along the flare's beam the element appears. "   
114   "A distance of 0.0 is directly over the light source, a distance of 1.0 "
115   "is at the screen center, and a distance of 2.0 is at the position of the "
116   "light source mirrored across the screen center.\n"
117   "@image html images/lightFlareData_diagram.png\n"
118   "@ingroup Lighting"   
119);
120
121LightFlareData::LightFlareData()
122 : mScale( 1.0f ),
123   mFlareEnabled( true ),
124   mOcclusionRadius( 0.0f ),
125   mRenderReflectPass( true ),
126   mElementCount( 0 )
127{
128   dMemset( mElementRect, 0, sizeof( RectF ) * MAX_ELEMENTS );   
129   dMemset( mElementScale, 0, sizeof( F32 ) * MAX_ELEMENTS );
130   dMemset( mElementTint, 0, sizeof( LinearColorF ) * MAX_ELEMENTS );
131   dMemset( mElementRotate, 0, sizeof( bool ) * MAX_ELEMENTS );
132   dMemset( mElementUseLightColor, 0, sizeof( bool ) * MAX_ELEMENTS );   
133
134   for ( U32 i = 0; i < MAX_ELEMENTS; i++ )   
135      mElementDist[i] = -1.0f;   
136}
137
138LightFlareData::~LightFlareData()
139{
140}
141
142void LightFlareData::initPersistFields()
143{
144   addGroup( "LightFlareData" );
145
146      addField( "overallScale", TypeF32, Offset( mScale, LightFlareData ),
147         "Size scale applied to all elements of the flare." );
148
149      addField( "occlusionRadius", TypeF32, Offset( mOcclusionRadius, LightFlareData ), 
150         "If positive an occlusion query is used to test flare visibility, else it uses simple raycasts." );
151
152      addField( "renderReflectPass", TypeBool, Offset( mRenderReflectPass, LightFlareData ), 
153         "If false the flare does not render in reflections, else only non-zero distance elements are rendered." );
154
155   endGroup( "LightFlareData" );
156
157   addGroup( "FlareElements" );
158
159      addField( "flareEnabled", TypeBool, Offset( mFlareEnabled, LightFlareData ),
160         "Allows the user to disable this flare globally for any lights referencing it." );
161
162      addField( "flareTexture", TypeImageFilename, Offset( mFlareTextureName, LightFlareData ),
163         "The texture / sprite sheet for this flare." );
164
165      addArray( "Elements", MAX_ELEMENTS );
166
167         addField( "elementRect", TypeRectF, Offset( mElementRect, LightFlareData ), MAX_ELEMENTS,
168            "A rectangle specified in pixels of the flareTexture image." );
169
170         addField( "elementDist", TypeF32, Offset( mElementDist, LightFlareData ), MAX_ELEMENTS,
171            "Where this element appears along the flare beam." );
172
173         addField( "elementScale", TypeF32, Offset( mElementScale, LightFlareData ), MAX_ELEMENTS,
174            "Size scale applied to this element." );
175
176         addField( "elementTint", TypeColorF, Offset( mElementTint, LightFlareData ), MAX_ELEMENTS,
177            "Used to modulate this element's color if elementUseLightColor "
178            "is false.\n"
179            "@see elementUseLightColor" );
180
181         addField( "elementRotate", TypeBool, Offset( mElementRotate, LightFlareData ), MAX_ELEMENTS,
182            "Defines if this element orients to point along the flare beam "
183            "or if it is always upright." );
184
185         addField( "elementUseLightColor", TypeBool, Offset( mElementUseLightColor, LightFlareData ), MAX_ELEMENTS,
186            "If true this element's color is modulated by the light color. "
187            "If false, elementTint will be used.\n"
188            "@see elementTint" );
189
190      endArray( "FlareElements" );
191
192   endGroup( "Flares" );
193
194   Parent::initPersistFields();
195}
196
197void LightFlareData::inspectPostApply()
198{
199   Parent::inspectPostApply();
200
201   // Hack to allow changing properties in game.
202   // Do the same work as preload.
203   
204   String str;
205   _preload( false, str );
206}
207
208bool LightFlareData::preload( bool server, String &errorStr )
209{
210   if ( !Parent::preload( server, errorStr ) )
211      return false;
212
213   return _preload( server, errorStr );
214}
215
216void LightFlareData::packData( BitStream *stream )
217{
218   Parent::packData( stream );
219
220   stream->writeFlag( mFlareEnabled );
221   stream->write( mFlareTextureName );   
222   stream->write( mScale );
223   stream->write( mOcclusionRadius );
224   stream->writeFlag( mRenderReflectPass );
225
226   stream->write( mElementCount );
227
228   for ( U32 i = 0; i < mElementCount; i++ )
229   {
230      mathWrite( *stream, mElementRect[i] );
231      stream->write( mElementDist[i] );
232      stream->write( mElementScale[i] );
233      stream->write( mElementTint[i] );
234      stream->writeFlag( mElementRotate[i] );
235      stream->writeFlag( mElementUseLightColor[i] );
236   }
237}
238
239void LightFlareData::unpackData( BitStream *stream )
240{
241   Parent::unpackData( stream );
242
243   mFlareEnabled = stream->readFlag();
244   stream->read( &mFlareTextureName );   
245   stream->read( &mScale );
246   stream->read( &mOcclusionRadius );
247   mRenderReflectPass = stream->readFlag();
248
249   stream->read( &mElementCount );
250
251   for ( U32 i = 0; i < mElementCount; i++ )
252   {
253      mathRead( *stream, &mElementRect[i] );
254      stream->read( &mElementDist[i] );
255      stream->read( &mElementScale[i] );
256      stream->read( &mElementTint[i] );
257      mElementRotate[i] = stream->readFlag();
258      mElementUseLightColor[i] = stream->readFlag();
259   }
260}
261
262bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareState *flareState, U32 *outVisDelta, F32 *outOcclusionFade, Point3F *outLightPosSS)
263{
264   // Reflections use the results from the last forward
265   // render so we don't need multiple queries.
266   if ( state->isReflectPass() )
267   {
268      *outOcclusionFade = flareState->occlusion;
269      *outVisDelta = Sim::getCurrentTime() - flareState->visChangedTime;
270      return flareState->visible;
271   }
272
273   // Initialize it to something first.
274   *outOcclusionFade = 0;
275
276   // First check to see if the flare point 
277   // is on scren at all... if not then return
278   // the last result.
279   const Point3F &lightPos = flareState->lightMat.getPosition();  
280   const RectI &viewport = RectI(Point2I(0, 0), GFX->getViewport().extent);
281   MatrixF camProjMatrix = state->getSceneManager()->getNonClipProjection();
282
283   bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), camProjMatrix );
284
285   // It is onscreen, so raycast as a simple occlusion test.
286   const LightInfo *lightInfo = flareState->lightInfo;
287   const bool isVectorLight = lightInfo->getType() == LightInfo::Vector;
288
289   const bool useOcclusionQuery = isVectorLight ? flareState->worldRadius > 0.0f : mOcclusionRadius > 0.0f;
290   bool needsRaycast = true;
291
292   // NOTE: if hardware does not support HOQ it will return NULL
293   // and we will retry every time but there is not currently a good place
294   // for one-shot initialization of LightFlareState
295   if ( useOcclusionQuery )
296   {
297      // Always treat light as onscreen if using HOQ
298      // it will be faded out if offscreen anyway.
299      onScreen = true;
300      needsRaycast = false;
301
302      // Test the hardware queries for rendered pixels.
303      U32 pixels = 0, fullPixels = 0;
304      GFXOcclusionQuery::OcclusionQueryStatus status;
305      flareState->occlusionQuery.getLastStatus( false, &status, &pixels );      
306      flareState->fullPixelQuery.getLastStatus( false, NULL, &fullPixels );
307      
308      if ( status == GFXOcclusionQuery::NotOccluded && fullPixels != 0 )
309         *outOcclusionFade = mClampF( (F32)pixels / (F32)fullPixels, 0.0f, 1.0f );
310
311        if( !flareState->occlusionQuery.isWaiting() )
312        {
313            // Setup the new queries.
314            RenderPassManager *rpm = state->getRenderPass();
315            OccluderRenderInst *ri = rpm->allocInst<OccluderRenderInst>();   
316            ri->type = RenderPassManager::RIT_Occluder;
317            ri->query = flareState->occlusionQuery.getQuery();
318            ri->query2 = flareState->fullPixelQuery.getQuery();
319            ri->isSphere = true;
320            ri->position = lightPos;
321            if ( isVectorLight && flareState->worldRadius > 0.0f )         
322                ri->scale.set( flareState->worldRadius );
323            else
324                ri->scale.set( mOcclusionRadius );
325            ri->orientation = rpm->allocUniqueXform( lightInfo->getTransform() );         
326      
327            // Submit the queries.
328            state->getRenderPass()->addInst( ri );
329        }
330   }
331
332   const Point3F &camPos = state->getCameraPosition();
333
334   if ( needsRaycast )
335   {
336      // Use a raycast to determine occlusion.
337      GameConnection *conn = GameConnection::getConnectionToServer();
338      if ( !conn )
339         return false;
340
341      const bool fps = conn->isFirstPerson();
342      GameBase *control = conn->getControlObject();
343      if ( control && fps )
344         control->disableCollision();
345
346      RayInfo rayInfo;
347
348      if ( !gClientContainer.castRay( camPos, lightPos, LosMask, &rayInfo ) )
349         *outOcclusionFade = 1.0f;
350
351      if ( control && fps )
352         control->enableCollision();
353   }
354
355   // The raycast and hardware occlusion query only calculate if
356   // the flare is on screen... if does not account for being 
357   // partially offscreen.
358   //
359   // The code here clips a box against the viewport to 
360   // get an approximate percentage of onscreen area.
361   //
362   F32 worldRadius = flareState->worldRadius > 0 ? flareState->worldRadius : mOcclusionRadius;
363   if ( worldRadius > 0.0f )
364   {
365      F32 dist = ( camPos - lightPos ).len();
366      F32 pixelRadius = state->projectRadius(dist, worldRadius);
367
368      RectI visRect( outLightPosSS->x - pixelRadius, outLightPosSS->y - pixelRadius, 
369                     pixelRadius * 2.0f, pixelRadius * 2.0f ); 
370      F32 fullArea = visRect.area();
371
372      if ( visRect.intersect( viewport ) )
373      {
374         F32 visArea = visRect.area();
375         *outOcclusionFade *= visArea / fullArea;
376         onScreen = true;
377      }
378      else
379         *outOcclusionFade = 0.0f;
380   }
381   
382   const bool lightVisible = onScreen && *outOcclusionFade > 0.0f;
383
384   // To perform a fade in/out when we gain or lose visibility
385   // we must update/store the visibility state and time.
386   const U32 currentTime = Sim::getCurrentTime();
387   if ( lightVisible != flareState->visible )
388   {
389      flareState->visible = lightVisible;
390      flareState->visChangedTime = currentTime;
391   }
392
393   // Return the visibility delta for time fading.
394   *outVisDelta = currentTime - flareState->visChangedTime;
395
396   // Store the final occlusion fade so that it can
397   // be used in reflection rendering later.
398   flareState->occlusion = *outOcclusionFade;
399
400   return lightVisible;
401}
402
403void LightFlareData::prepRender(SceneRenderState *state, LightFlareState *flareState)
404{
405   PROFILE_SCOPE(LightFlareData_prepRender);
406
407   const LightInfo *lightInfo = flareState->lightInfo;
408
409   if (mIsZero(flareState->fullBrightness) ||
410       mIsZero(lightInfo->getBrightness()))
411   return;
412
413   // Figure out the element count to render.
414   U32 elementCount = mElementCount;
415   const bool isReflectPass = state->isReflectPass();
416   if (isReflectPass)
417   {
418      // Then we don't render anything this pass.
419      if (!mRenderReflectPass)
420         return;
421
422      // Find the zero distance elements which make 
423      // up the corona of the light flare.
424      elementCount = 0.0f;
425      for (U32 i = 0; i < mElementCount; i++)
426         if (mIsZero(mElementDist[i]))
427      elementCount++;
428   }
429
430   // Better have something to render.
431   if (elementCount == 0)
432      return;
433
434   U32 visDelta = U32_MAX;
435   F32 occlusionFade = 1.0f;
436   Point3F lightPosSS;
437   bool lightVisible = _testVisibility(state, flareState, &visDelta, &occlusionFade, &lightPosSS);
438
439   //DebugDrawer::get()->drawBox(flareState->lightMat.getPosition() + Point3F(-0.5, -0.5, -0.5) * 4, flareState->lightMat.getPosition() + Point3F(0.5, 0.5, 0.5) * 4, ColorI::BLUE);
440
441   // We can only skip rendering if the light is not 
442   // visible, and it has elapsed the fade out time.
443   if (mIsZero(occlusionFade) ||
444      (!lightVisible && visDelta > FadeOutTime))
445      return;
446
447   const RectI &viewport = GFX->getViewport();
448   Point3F oneOverViewportExtent(1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f);
449
450   lightPosSS *= oneOverViewportExtent;
451   lightPosSS = (lightPosSS * 2.0f) - Point3F::One;
452   lightPosSS.y = -lightPosSS.y;
453   lightPosSS.z = 0.0f;
454
455   // Determine the center of the current projection so we can converge there
456   Point3F centerProj(0);
457   {
458      MatrixF camProjMatrix = state->getSceneManager()->getNonClipProjection();
459      Point3F outCenterPos;
460      RectI centerViewport = RectI(Point2I(0, 0), viewport.extent);
461      MathUtils::mProjectWorldToScreen(Point3F(0,state->getSceneManager()->getNearClip(),0), &outCenterPos, centerViewport, MatrixF::Identity, camProjMatrix);
462      centerProj = outCenterPos;
463      centerProj *= oneOverViewportExtent;
464      centerProj = (centerProj * 2.0f) - Point3F::One;
465      centerProj.y = -centerProj.y;
466      centerProj.z = 0.0f;
467   }
468
469   // Take any projection offset into account so that the point where the flare's
470   // elements converge is at the 'eye' point rather than the center of the viewport.
471   Point3F flareVec( centerProj - lightPosSS );
472   const F32 flareLength = flareVec.len();
473   if ( flareLength > 0.0f )
474      flareVec *= 1.0f / flareLength;
475
476   // Setup the flare quad points.
477   Point3F rotatedBasePoints[4];
478   dMemcpy(rotatedBasePoints, sBasePoints, sizeof( sBasePoints ));
479
480   // Rotate the flare quad.
481   F32 rot = mAcos( -1.0f * flareVec.x );
482   rot *= flareVec.y > 0.0f ? -1.0f : 1.0f;
483   MathUtils::vectorRotateZAxis( rot, rotatedBasePoints, 4 );
484
485   // Here we calculate a the light source's influence on 
486   // the effect's size and brightness.
487
488   // Scale based on the current light brightness compared to its normal output.
489   F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness;
490
491   const Point3F &camPos = state->getCameraPosition();
492   const Point3F &lightPos = flareState->lightMat.getPosition();   
493   const bool isVectorLight = lightInfo->getType() == LightInfo::Vector;
494
495   // Scale based on world space distance from camera to light source.
496   F32 distToCamera = ( camPos - lightPos ).len();
497   F32 lightSourceWSDistanceScale = isVectorLight && distToCamera > 0.0f ? 1.0f : getMin( 10.0f / distToCamera, 10.0f );
498
499   // Scale based on screen space distance from screen position of light source to the screen center.
500   F32 lightSourceSSDistanceScale = getMax( ( 1.5f - flareLength ) / 1.5f, 0.0f );
501
502   // Scale based on recent visibility changes, fading in or out.
503   F32 fadeInOutScale = 1.0f;   
504   if (  lightVisible &&
505         visDelta < FadeInTime && 
506         flareState->occlusion > 0.0f )
507      fadeInOutScale = (F32)visDelta / (F32)FadeInTime;
508   else if (   !lightVisible && 
509               visDelta < FadeOutTime )
510      fadeInOutScale = 1.0f - (F32)visDelta / (F32)FadeOutTime;
511
512   // This combined scale influences the size of all elements this effect renders.
513   // Note we also add in a scale that is user specified in the Light.
514   F32 lightSourceIntensityScale = lightSourceBrightnessScale * 
515                                   lightSourceWSDistanceScale * 
516                                   lightSourceSSDistanceScale * 
517                                   fadeInOutScale * 
518                                   flareState->scale *
519                                   occlusionFade;
520
521   if ( mIsZero( lightSourceIntensityScale ) )
522      return;
523
524   // The baseColor which modulates the color of all elements.
525   //
526   // These are the factors which affect the "alpha" of the flare effect.
527   // Modulate more in as appropriate.
528   LinearColorF baseColor = LinearColorF::WHITE * lightSourceBrightnessScale * occlusionFade;
529
530   // Setup the vertex buffer for the maximum flare elements.
531   const U32 vertCount = 4 * mElementCount;
532   if (  flareState->vertBuffer.isNull() || 
533         flareState->vertBuffer->mNumVerts != vertCount )
534         flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic );
535
536   GFXVertexPCT *vert = flareState->vertBuffer.lock();
537
538   const Point2F oneOverTexSize( 1.0f / (F32)mFlareTexture.getWidth(), 1.0f / (F32)mFlareTexture.getHeight() );
539
540   for ( U32 i = 0; i < mElementCount; i++ )
541   {      
542      // Skip non-zero elements for reflections.
543      if ( isReflectPass && mElementDist[i] > 0.0f )
544         continue;
545
546      Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : sBasePoints;
547
548      LinearColorF color( baseColor * mElementTint[i] );
549      if ( mElementUseLightColor[i] )
550         color *= lightInfo->getColor();
551      color.clamp();
552
553      Point3F pos( lightPosSS + flareVec * mElementDist[i] * flareLength );
554
555      const RectF &rect = mElementRect[i];
556      Point3F size( rect.extent.x, rect.extent.y, 1.0f );
557      size *= mElementScale[i] * mScale * lightSourceIntensityScale;
558
559      AssertFatal( size.x >= 0.0f, "LightFlareData::prepRender - Got a negative element size?" );
560
561      if ( size.x < 100.0f )
562      {
563         F32 alphaScale = mPow( size.x / 100.0f, 2 );
564         color *= alphaScale;
565      }
566
567      Point2F texCoordMin, texCoordMax;
568      texCoordMin = rect.point * oneOverTexSize;
569      texCoordMax = ( rect.point + rect.extent ) * oneOverTexSize;          
570
571      size.x = getMax( size.x, 1.0f );
572      size.y = getMax( size.y, 1.0f );
573      size *= oneOverViewportExtent;
574
575      const ColorI colori = color.toColorI();
576      vert->color = colori;
577      vert->point = ( basePos[0] * size ) + pos;      
578      vert->texCoord.set( texCoordMin.x, texCoordMax.y );
579      vert++;
580
581      vert->color = colori;
582      vert->point = ( basePos[1] * size ) + pos;
583      vert->texCoord.set( texCoordMax.x, texCoordMax.y );
584      vert++;
585
586      vert->color = colori;
587      vert->point = ( basePos[2] * size ) + pos;
588      vert->texCoord.set( texCoordMax.x, texCoordMin.y );
589      vert++;
590
591      vert->color = colori;
592      vert->point = ( basePos[3] * size ) + pos;
593      vert->texCoord.set( texCoordMin.x, texCoordMin.y );
594      vert++;
595   }   
596
597   flareState->vertBuffer.unlock();   
598
599   RenderPassManager *rpm = state->getRenderPass();
600
601   // Create and submit the render instance.   
602   ParticleRenderInst *ri = rpm->allocInst<ParticleRenderInst>();
603   ri->type = RenderPassManager::RIT_Particle;
604   ri->vertBuff = &flareState->vertBuffer;
605   ri->primBuff = &mFlarePrimBuffer;
606   ri->translucentSort = true;
607   ri->sortDistSq = ( lightPos - camPos ).lenSquared();
608   ri->modelViewProj = &MatrixF::Identity;
609   ri->bbModelViewProj = &MatrixF::Identity;
610   ri->count = elementCount;
611   ri->blendStyle = ParticleRenderInst::BlendGreyscale;
612   ri->diffuseTex = mFlareTexture;
613   ri->softnessDistance = 1.0f; 
614   ri->defaultKey = ri->diffuseTex ? (uintptr_t)ri->diffuseTex : (uintptr_t)ri->vertBuff; // Sort by texture too.
615
616   // NOTE: Offscreen partical code is currently disabled.
617   ri->systemState = PSS_AwaitingHighResDraw;
618
619   rpm->addInst( ri );
620}
621
622bool LightFlareData::_preload( bool server, String &errorStr )
623{
624   mElementCount = 0;
625   for ( U32 i = 0; i < MAX_ELEMENTS; i++ )
626   {
627      if ( mElementDist[i] == -1 )
628         break;
629      mElementCount = i + 1;
630   }   
631
632   if ( mElementCount > 0 )
633      _makePrimBuffer( &mFlarePrimBuffer, mElementCount );
634
635   if ( !server )
636   {
637      if ( mFlareTextureName.isNotEmpty() )      
638         mFlareTexture.set( mFlareTextureName, &GFXStaticTextureSRGBProfile, "FlareTexture" );
639   }
640
641   return true;
642}
643
644void LightFlareData::_makePrimBuffer( GFXPrimitiveBufferHandle *pb, U32 count )
645{
646   // create index buffer based on that size
647   U32 indexListSize = count * 6; // 6 indices per particle
648   U16 *indices = new U16[ indexListSize ];
649
650   for ( U32 i = 0; i < count; i++ )
651   {
652      // this index ordering should be optimal (hopefully) for the vertex cache
653      U16 *idx = &indices[i*6];
654      volatile U32 offset = i * 4;  // set to volatile to fix VC6 Release mode compiler bug
655      idx[0] = 0 + offset;
656      idx[1] = 1 + offset;
657      idx[2] = 3 + offset;
658      idx[3] = 1 + offset;
659      idx[4] = 3 + offset;
660      idx[5] = 2 + offset; 
661   }
662
663   U16 *ibIndices;
664   GFXBufferType bufferType = GFXBufferTypeStatic;
665
666   pb->set( GFX, indexListSize, 0, bufferType );
667   pb->lock( &ibIndices );
668   dMemcpy( ibIndices, indices, indexListSize * sizeof(U16) );
669   pb->unlock();
670
671   delete [] indices;
672}
673
674DefineEngineMethod( LightFlareData, apply, void, (),,
675                   "Intended as a helper to developers and editor scripts.\n"
676                   "Force trigger an inspectPostApply"
677                   )
678{
679   object->inspectPostApply();
680}
681