text: //-----------------------------------------------------------------------------
  // 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 "T3D/lighting/Skylight.h"
  #include "math/mathIO.h"
  #include "scene/sceneRenderState.h"
  #include "console/consoleTypes.h"
  #include "core/stream/bitStream.h"
  #include "materials/baseMatInstance.h"
  #include "console/engineAPI.h"
  #include "gfx/gfxDrawUtil.h"
  #include "gfx/gfxDebugEvent.h"
  #include "gfx/gfxTransformSaver.h"
  #include "math/mathUtils.h"
  #include "gfx/bitmap/gBitmap.h"
  #include "core/stream/fileStream.h"
  #include "core/fileObject.h"
  #include "core/resourceManager.h"
  #include "console/simPersistId.h"
  #include "T3D/gameFunctions.h"
  #include "postFx/postEffect.h"
  #include "renderInstance/renderProbeMgr.h"
  #include "lighting/probeManager.h"
  
  #include "math/util/sphereMesh.h"
  #include "materials/materialManager.h"
  #include "math/util/matrixSet.h"
  #include "gfx/bitmap/cubemapSaver.h"
  
  #include "materials/materialFeatureTypes.h"
  
  #include "materials/shaderData.h"
  #include "gfx/gfxTextureManager.h"
  
  #include "gfx/bitmap/imageUtils.h"
  
  #include "T3D/lighting/IBLUtilities.h"
  
  extern bool gEditingMission;
  extern ColorI gCanvasClearColor;
  bool Skylight::smRenderSkylights = true;
  
  IMPLEMENT_CO_NETOBJECT_V1(Skylight);
  
  ConsoleDocClass(Skylight,
     "@brief An example scene object which renders a mesh.\n\n"
     "This class implements a basic SceneObject that can exist in the world at a "
     "3D position and render itself. There are several valid ways to render an "
     "object in Torque. This class implements the preferred rendering method which "
     "is to submit a MeshRenderInst along with a Material, vertex buffer, "
     "primitive buffer, and transform and allow the RenderMeshMgr handle the "
     "actual setup and rendering for you.\n\n"
     "See the C++ code for implementation details.\n\n"
     "@ingroup Examples\n");
  
  //-----------------------------------------------------------------------------
  // Object setup and teardown
  //-----------------------------------------------------------------------------
  Skylight::Skylight() : ReflectionProbe()
  {
     mCaptureMask = SKYLIGHT_CAPTURE_TYPEMASK;
  }
  
  Skylight::~Skylight()
  {
  }
  
  //-----------------------------------------------------------------------------
  // Object Editing
  //-----------------------------------------------------------------------------
  void Skylight::initPersistFields()
  {
     // SceneObject already handles exposing the transform
     Parent::initPersistFields();
  }
  
  void Skylight::inspectPostApply()
  {
     Parent::inspectPostApply();
  
     mDirty = true;
  
     // Flag the network mask to send the updates
     // to the client object
     setMaskBits(-1);
  }
  
  bool Skylight::onAdd()
  {
     if (!Parent::onAdd())
        return false;
  
     return true;
  }
  
  void Skylight::onRemove()
  {
     Parent::onRemove();
  }
  
  void Skylight::setTransform(const MatrixF & mat)
  {
     // Let SceneObject handle all of the matrix manipulation
     Parent::setTransform(mat);
  
     mDirty = true;
  
     // Dirty our network mask so that the new transform gets
     // transmitted to the client object
     setMaskBits(TransformMask);
  }
  
  U32 Skylight::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
  {
     // Allow the Parent to get a crack at writing its info
     U32 retMask = Parent::packUpdate(conn, mask, stream);
  
     return retMask;
  }
  
  void Skylight::unpackUpdate(NetConnection *conn, BitStream *stream)
  {
     // Let the Parent read any info it sent
     Parent::unpackUpdate(conn, stream);
  }
  
  //-----------------------------------------------------------------------------
  // Object Rendering
  //-----------------------------------------------------------------------------
  
  void Skylight::updateProbeParams()
  {
     Parent::updateProbeParams();
  
     mProbeInfo->mProbeShapeType = ProbeRenderInst::Sphere;
  
     mProbeInfo->setPosition(getPosition());
  
     // Skip our transform... it just dirties mask bits.
     Parent::setTransform(mObjToWorld);
  
     resetWorldBox();
  
     F32 visDist = gClientSceneGraph->getVisibleDistance();
     Box3F skylightBounds = Box3F(visDist * 2);
  
     skylightBounds.setCenter(Point3F::Zero);
  
     mProbeInfo->setPosition(Point3F::Zero);
  
     mProbeInfo->mBounds = skylightBounds;
  
     setGlobalBounds();
  
     mProbeInfo->mAmbient = LinearColorF(1, 1, 1, 1);
  
     mProbeInfo->mIsSkylight = true; 
     mProbeInfo->mScore = -1.0f; //sky comes first
  }
  
  void Skylight::prepRenderImage(SceneRenderState *state)
  {
     if (!mEnabled || !Skylight::smRenderSkylights)
        return;
  
     //special hook-in for skylights
     Point3F camPos = state->getCameraPosition();
     mProbeInfo->mBounds.setCenter(camPos);
  
     mProbeInfo->setPosition(camPos);
  
     //Submit our probe to actually do the probe action
     // Get a handy pointer to our RenderPassmanager
     //RenderPassManager *renderPass = state->getRenderPass();
  
     //PROBEMGR->registerSkylight(mProbeInfo, this);
  
     if (Skylight::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr)
     {
        GFXTransformSaver saver;
  
        // Calculate the distance of this object from the camera
        Point3F cameraOffset;
        getRenderTransform().getColumn(3, &cameraOffset);
        cameraOffset -= state->getDiffuseCameraPosition();
        F32 dist = cameraOffset.len();
        if (dist < 0.01f)
           dist = 0.01f;
  
        // Set up the LOD for the shape
        F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
  
        mEditorShapeInst->setDetailFromDistance(state, dist * invScale);
  
        // Make sure we have a valid level of detail
        if (mEditorShapeInst->getCurrentDetail() < 0)
           return;
  
        BaseMatInstance* probePrevMat = mEditorShapeInst->getMaterialList()->getMaterialInst(0);
  
        setPreviewMatParameters(state, probePrevMat);
  
        // GFXTransformSaver is a handy helper class that restores
        // the current GFX matrices to their original values when
        // it goes out of scope at the end of the function
  
        // Set up our TS render state      
        TSRenderState rdata;
        rdata.setSceneState(state);
        rdata.setFadeOverride(1.0f);
  
        // We might have some forward lit materials
        // so pass down a query to gather lights.
        LightQuery query;
        query.init(getWorldSphere());
        rdata.setLightQuery(&query);
  
        // Set the world matrix to the objects render transform
        MatrixF mat = getRenderTransform();
        mat.scale(Point3F(1, 1, 1));
        GFX->setWorldMatrix(mat);
  
        // Animate the the shape
        mEditorShapeInst->animate();
  
        // Allow the shape to submit the RenderInst(s) for itself
        mEditorShapeInst->render(rdata);
  
        saver.restore();
     }
  
     // If the light is selected or light visualization
     // is enabled then register the callback.
     const bool isSelectedInEditor = (gEditingMission && isSelected());
     if (isSelectedInEditor)
     {
     }
  }
  
  void Skylight::setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat)
  {
     Parent::setPreviewMatParameters(renderState, mat);
  }
  
  DefineEngineMethod(Skylight, postApply, void, (), ,
     "A utility method for forcing a network update.\n")
  {
     object->inspectPostApply();
  }