bool blTerrainProxy::getPersistInfo(PersistInfo::PersistChunk * info)
{
   if(!Parent::getPersistInfo(info))
      return(false);

   blTerrainChunk * chunk = dynamic_cast<blTerrainChunk*>(info);
   AssertFatal(chunk, "blTerrainProxy::getPersistInfo: invalid info chunk!");

   TerrainBlock * terrain = getObject();
   if(!terrain || !terrain->getLightMap())
      return(false);

   if(chunk->mLightmap) delete chunk->mLightmap;

   chunk->mLightmap = new GBitmap(*terrain->getLightMap());

   return(true);
}
// Given a ray, this will return the color from the lightmap of this object, return true if handled
bool blTerrainSystem::getColorFromRayInfo(const RayInfo & collision, ColorF& result) const
{
   TerrainBlock *terrain = dynamic_cast<TerrainBlock *>(collision.object);
   if (!terrain)
      return false;

   Point2F uv;
   F32 terrainlength = (F32)terrain->getBlockSize();
   Point3F pos = terrain->getPosition();
   uv.x = (collision.point.x - pos.x) / terrainlength;
   uv.y = (collision.point.y - pos.y) / terrainlength;

   // similar to x = x & width...
   uv.x = uv.x - F32(U32(uv.x));
   uv.y = uv.y - F32(U32(uv.y));
   const GBitmap* lightmap = terrain->getLightMap();
   if (!lightmap)
      return false;

   result = lightmap->sampleTexel(uv.x, uv.y);
   // terrain lighting is dim - look into this (same thing done in shaders)...
   result *= 2.0f;
   return true;
}
void blTerrainProxy::light(LightInfo * light)
{
   // If we don't have terrain or its not a directional
   // light then skip processing.
   TerrainBlock * terrain = getObject();
   if ( !terrain || light->getType() != LightInfo::Vector )
      return;

   S32 time = Platform::getRealMilliseconds();

   // reset
   mShadowVolume = new ShadowVolumeBSP;

   // build interior shadow volume
   for(ObjectProxy ** itr = gLighting->mLitObjects.begin(); itr != gLighting->mLitObjects.end(); itr++)
   {
      ObjectProxy* objproxy = *itr;
      if (markObjectShadow(objproxy))
         objproxy->addToShadowVolume(mShadowVolume, light, SceneLighting::SHADOW_DETAIL);
   }

   lightVector(light);

   // set the lightmap...
   terrain->clearLightMap();

   // Blur...
   F32 kernel[3][3] = { {1, 2, 1},
                        {2, 3, 2},
                        {1, 2, 1} };

   F32 modifier = 1;
   F32 divisor = 0;


   for( U32 i=0; i<3; i++ )
   {
      for( U32 j=0; j<3; j++ )
      {
         if( i==1 && j==1 )
         {
            kernel[i][j] = 1 + kernel[i][j] * modifier;
         }
         else
         {
            kernel[i][j] = kernel[i][j] * modifier;
         }

         divisor += kernel[i][j];
      }
   }

   for( U32 i=0; i < mLightMapSize; i++ )
   {
      for( U32 j=0; j < mLightMapSize; j++ )
      {

         ColorF val;
         val  = _getValue( i-1, j-1  ) * kernel[0][0];
         val += _getValue( i-1, j    ) * kernel[0][1];
         val += _getValue( i-1, j+1  ) * kernel[0][2];
         val += _getValue(   i, j-1  ) * kernel[1][0];
         val += _getValue(   i, j    ) * kernel[1][1];
         val += _getValue(   i, j+1  ) * kernel[1][2];
         val += _getValue( i+1, j-1  ) * kernel[2][0];
         val += _getValue( i+1, j    ) * kernel[2][1];
         val += _getValue( i+1, j+1  ) * kernel[2][2];

         U32 edge = 0;

         if( j == 0 || j == mLightMapSize - 1 )
            edge++;

         if( i == 0 || i == mLightMapSize - 1 )
            edge++;

         if( !edge )
            val = val / divisor;
         else
            val = mLightmap[ i * mLightMapSize + j ];

         // clamp values
         mLightmap[ i * mLightMapSize + j ]= val;
      }
   }

   // And stuff it into the texture...
   GBitmap *terrLightMap = terrain->getLightMap();
   for(U32 y = 0; y < mLightMapSize; y++)
   {
      for(U32 x = 0; x < mLightMapSize; x++)
      {
         ColorI color(255, 255, 255, 255);
         
         color.red   = mLightmap[x + y * mLightMapSize].red   * 255;
         color.green = mLightmap[x + y * mLightMapSize].green * 255;
         color.blue  = mLightmap[x + y * mLightMapSize].blue  * 255;

         terrLightMap->setColor(x, y, color);
      }
   }

   /*
   // This handles matching up the outer edges of the terrain
   // lightmap when it has neighbors
   if (!terrain->isTiling())
   {
      for (S32 y = 0; y < terrLightMap->getHeight(); y++)
      {
         ColorI c;
         if (terrain->getFile()->mEdgeTerrainFiles[0])
         {
            terrLightMap->getColor(terrLightMap->getWidth()-1,y,c);
            terrLightMap->setColor(0,y,c);
            terrLightMap->setColor(1,y,c);
         }
         else
         {
            terrLightMap->getColor(0,y,c);
            terrLightMap->setColor(terrLightMap->getWidth()-1,y,c);
            terrLightMap->setColor(terrLightMap->getWidth()-2,y,c);
         }
      }

      for (S32 x = 0; x < terrLightMap->getHeight(); x++)
      {
         ColorI c;
         if (terrain->getFile()->mEdgeTerrainFiles[1])
         {
            terrLightMap->getColor(x,terrLightMap->getHeight()-1,c);
            terrLightMap->setColor(x,0,c);
            terrLightMap->setColor(x,1,c);
         }
         else
         {
            terrLightMap->getColor(x,0,c);
            terrLightMap->setColor(x,terrLightMap->getHeight()-1,c);
            terrLightMap->setColor(x,terrLightMap->getHeight()-2,c);
         }
      }
   }
   */

   delete mShadowVolume;

   Con::printf("    = terrain lit in %3.3f seconds", (Platform::getRealMilliseconds()-time)/1000.f);
}