//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "platform/platform.h" #include "T3D/lightDescription.h" #include "lighting/lightManager.h" #include "T3D/lightFlareData.h" #include "T3D/lightAnimData.h" #include "core/stream/bitStream.h" #include "lighting/lightInfo.h" #include "console/engineAPI.h" LightDescription::LightDescription() : color( LinearColorF::WHITE ), brightness( 1.0f ), range( 5.0f ), castShadows( false ), mStaticRefreshFreq( 250 ), mDynamicRefreshFreq( 8 ), animationData( NULL ), animationDataId( 0 ), animationPeriod( 1.0f ), animationPhase( 1.0f ), flareData( NULL ), flareDataId( 0 ), flareScale( 1.0f ) { } LightDescription::~LightDescription() { } IMPLEMENT_CO_DATABLOCK_V1( LightDescription ); ConsoleDocClass( LightDescription, "@brief A helper datablock used by classes (such as shapebase) " "that submit lights to the scene but do not use actual \"LightBase\" objects.\n\n" "This datablock stores the properties of that light as fields that can be initialized from script." "@tsexample\n" "// Declare a light description to be used on a rocket launcher projectile\n" "datablock LightDescription(RocketLauncherLightDesc)\n" "{\n" " range = 4.0;\n" " color = \"1 1 0\";\n" " brightness = 5.0;\n" " animationType = PulseLightAnim;\n" " animationPeriod = 0.25;\n" "};\n\n" "// Declare a ProjectileDatablock which uses the light description\n" "datablock ProjectileData(RocketLauncherProjectile)\n" "{\n" " lightDesc = RocketLauncherLightDesc;\n\n" " projectileShapeName = \"art/shapes/weapons/SwarmGun/rocket.dts\";\n\n" " directDamage = 30;\n" " radiusDamage = 30;\n" " damageRadius = 5;\n" " areaImpulse = 2500;\n\n" " // ... remaining ProjectileData fields not listed for this example\n" "};\n" "@endtsexample\n\n" "@see LightBase\n\n" "@ingroup Lighting\n" ); void LightDescription::initPersistFields() { docsURL; addGroup( "Light" ); addField( "color", TypeColorF, Offset( color, LightDescription ), "Changes the base color hue of the light." ); addField( "brightness", TypeF32, Offset( brightness, LightDescription ), "Adjusts the lights power, 0 being off completely." ); addField( "range", TypeF32, Offset( range, LightDescription ), "Controls the size (radius) of the light" ); addField( "castShadows", TypeBool, Offset( castShadows, LightDescription ), "Enables/disabled shadow casts by this light." ); addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightDescription ), "static shadow refresh rate (milliseconds)" ); addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightDescription ), "dynamic shadow refresh rate (milliseconds)"); endGroup( "Light" ); addGroup( "Light Animation" ); addField( "animationType", TYPEID< LightAnimData >(), Offset( animationData, LightDescription ), "Datablock containing light animation information (LightAnimData)" ); addField( "animationPeriod", TypeF32, Offset( animationPeriod, LightDescription ), "The length of time in seconds for a single playback of the light animation" ); addField( "animationPhase", TypeF32, Offset( animationPhase, LightDescription ), "The phase used to offset the animation start time to vary the animation of nearby lights." ); endGroup( "Light Animation" ); addGroup( "Misc" ); addField( "flareType", TYPEID< LightFlareData >(), Offset( flareData, LightDescription ), "Datablock containing light flare information (LightFlareData)" ); addField( "flareScale", TypeF32, Offset( flareScale, LightDescription ), "Globally scales all features of the light flare" ); endGroup( "Misc" ); LightManager::initLightFields(); Parent::initPersistFields(); } void LightDescription::inspectPostApply() { Parent::inspectPostApply(); // Hack to allow changing properties in game. // Do the same work as preload. animationData = NULL; flareData = NULL; String str; _preload( false, str ); } bool LightDescription::onAdd() { if ( !Parent::onAdd() ) return false; return true; } bool LightDescription::preload( bool server, String &errorStr ) { if ( !Parent::preload( server, errorStr ) ) return false; return _preload( server, errorStr ); } void LightDescription::packData( BitStream *stream ) { Parent::packData( stream ); stream->write( color ); stream->write( brightness ); stream->write( range ); stream->writeFlag( castShadows ); stream->write(mStaticRefreshFreq); stream->write(mDynamicRefreshFreq); stream->write( animationPeriod ); stream->write( animationPhase ); stream->write( flareScale ); if ( stream->writeFlag( animationData ) ) { stream->writeRangedU32( animationData->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); } if ( stream->writeFlag( flareData ) ) { stream->writeRangedU32( flareData->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast ); } } void LightDescription::unpackData( BitStream *stream ) { Parent::unpackData( stream ); stream->read( &color ); stream->read( &brightness ); stream->read( &range ); castShadows = stream->readFlag(); stream->read(&mStaticRefreshFreq); stream->read(&mDynamicRefreshFreq); stream->read( &animationPeriod ); stream->read( &animationPhase ); stream->read( &flareScale ); if ( stream->readFlag() ) animationDataId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); if ( stream->readFlag() ) flareDataId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); } void LightDescription::submitLight( LightState *state, const MatrixF &xfm, LightManager *lm, SimObject *object ) { LightInfo *li = state->lightInfo; li->setRange( range ); li->setColor( color ); li->setCastShadows( castShadows ); li->setStaticRefreshFreq(mStaticRefreshFreq); li->setDynamicRefreshFreq(mDynamicRefreshFreq); li->setTransform( xfm ); if ( animationData ) { LightAnimState *animState = &state->animState; animState->brightness = brightness; animState->transform = xfm; animState->color = color; animState->animationPeriod = animationPeriod; animState->animationPhase = animationPhase; animationData->animate( li, animState ); } lm->registerGlobalLight( li, object ); } void LightDescription::prepRender( SceneRenderState *sceneState, LightState *lightState, const MatrixF &xfm ) { if ( flareData ) { LightFlareState *flareState = &lightState->flareState; flareState->fullBrightness = brightness; flareState->scale = flareScale; flareState->lightMat = xfm; flareState->lightInfo = lightState->lightInfo; flareData->prepRender( sceneState, flareState ); } } bool LightDescription::_preload( bool server, String &errorStr ) { if (!animationData && animationDataId != 0) if (Sim::findObject(animationDataId, animationData) == false) Con::errorf(ConsoleLogEntry::General, "LightDescription::onAdd: Invalid packet, bad datablockId(animationData): %d", animationDataId); if (!flareData && flareDataId != 0) if (Sim::findObject(flareDataId, flareData) == false) Con::errorf(ConsoleLogEntry::General, "LightDescription::onAdd: Invalid packet, bad datablockId(flareData): %d", flareDataId); return true; } DefineEngineMethod( LightDescription, apply, void, (),, "@brief Force an inspectPostApply call for the benefit of tweaking via the console\n\n" "Normally this functionality is only exposed to objects via the World Editor, once changes have been made. " "Exposing apply to script allows you to make changes to it on the fly without the World Editor.\n\n" "@note This is intended for debugging and tweaking, not for game play\n\n" "@tsexample\n" "// Change a property of the light description\n" "RocketLauncherLightDesc.brightness = 10;\n\n" "// Make it so\n" "RocketLauncherLightDesc.apply();\n" "@endtsexample\n\n" ) { object->inspectPostApply(); } //ConsoleMethod( LightDescription, apply, void, 2, 2, "force an inspectPostApply for the benefit of tweaking via the console" ) //{ // object->inspectPostApply(); //}