lightFlareData.cpp
Engine/source/T3D/lightFlareData.cpp
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