void doTerrainModify( Terrain* terrain, const Vector3& centrepos, Real timeElapsed )
  {
    Vector3 tsPos;
    terrain->getTerrainPosition( centrepos, &tsPos );
#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
    if( mInputContext.isKeyDown( OIS::KC_EQUALS ) || mInputContext.isKeyDown( OIS::KC_ADD ) ||
      mInputContext.isKeyDown( OIS::KC_MINUS ) || mInputContext.isKeyDown( OIS::KC_SUBTRACT ) )
    {
      switch( mMode )
      {
        case MODE_EDIT_HEIGHT:
        {
          // we need point coords
          Real terrainSize = (terrain->getSize() - 1);
          long startx = (tsPos.x - mBrushSizeTerrainSpace) * terrainSize;
          long starty = (tsPos.y - mBrushSizeTerrainSpace) * terrainSize;
          long endx = (tsPos.x + mBrushSizeTerrainSpace) * terrainSize;
          long endy = (tsPos.y + mBrushSizeTerrainSpace) * terrainSize;
          startx = std::max( startx, 0L );
          starty = std::max( starty, 0L );
          endx = std::min( endx, (long) terrainSize );
          endy = std::min( endy, (long) terrainSize );
          for( long y = starty; y <= endy; ++y )
          {
            for( long x = startx; x <= endx; ++x )
            {
              Real tsXdist = (x / terrainSize) - tsPos.x;
              Real tsYdist = (y / terrainSize) - tsPos.y;

              Real weight = std::min( (Real)1.0,
                Math::Sqrt( tsYdist * tsYdist + tsXdist * tsXdist ) / Real( 0.5 * mBrushSizeTerrainSpace ) );
              weight = 1.0 - (weight * weight);

              float addedHeight = weight * 250.0 * timeElapsed;
              float newheight;
              if( mInputContext.isKeyDown( OIS::KC_EQUALS ) || mInputContext.isKeyDown( OIS::KC_ADD ) )
                newheight = terrain->getHeightAtPoint( x, y ) + addedHeight;
              else
                newheight = terrain->getHeightAtPoint( x, y ) - addedHeight;
              terrain->setHeightAtPoint( x, y, newheight );

            }
          }
          if( mHeightUpdateCountDown == 0 )
            mHeightUpdateCountDown = mHeightUpdateRate;
        }
        break;
        case MODE_EDIT_BLEND:
        {
          TerrainLayerBlendMap* layer = terrain->getLayerBlendMap( mLayerEdit );
          // we need image coords
          Real imgSize = terrain->getLayerBlendMapSize();
          long startx = (tsPos.x - mBrushSizeTerrainSpace) * imgSize;
          long starty = (tsPos.y - mBrushSizeTerrainSpace) * imgSize;
          long endx = (tsPos.x + mBrushSizeTerrainSpace) * imgSize;
          long endy = (tsPos.y + mBrushSizeTerrainSpace) * imgSize;
          startx = std::max( startx, 0L );
          starty = std::max( starty, 0L );
          endx = std::min( endx, (long) imgSize );
          endy = std::min( endy, (long) imgSize );
          for( long y = starty; y <= endy; ++y )
          {
            for( long x = startx; x <= endx; ++x )
            {
              Real tsXdist = (x / imgSize) - tsPos.x;
              Real tsYdist = (y / imgSize) - tsPos.y;

              Real weight = std::min( (Real)1.0,
                Math::Sqrt( tsYdist * tsYdist + tsXdist * tsXdist ) / Real( 0.5 * mBrushSizeTerrainSpace ) );
              weight = 1.0 - (weight * weight);

              float paint = weight * timeElapsed;
              size_t imgY = imgSize - y;
              float val;
              if( mInputContext.isKeyDown( OIS::KC_EQUALS ) || mInputContext.isKeyDown( OIS::KC_ADD ) )
                val = layer->getBlendValue( x, imgY ) + paint;
              else
                val = layer->getBlendValue( x, imgY ) - paint;
              val = Math::Clamp( val, 0.0f, 1.0f );
              layer->setBlendValue( x, imgY, val );

            }
          }
          layer->update();
        }
        break;
        case MODE_NORMAL:
        case MODE_COUNT:
          break;
      };
    }
#endif
  }
Example #2
0
void TerrainGeometryManager::initBlendMaps(int x, int z, Ogre::Terrain* terrain )
{
	bool debugBlendMaps = BOPT("DebugBlendMaps", false);

	int layerCount = terrain->getLayerCount();
	for (int i = 1; i < layerCount; i++)
	{
		blendLayerInfo_t &bi = blendInfo[i];

		if(bi.blendMapTextureFilename.empty()) continue;

		Ogre::Image img;
		//std::pair<uint8,uint8> textureIndex = terrain->getLayerBlendTextureIndex(i);
		//uint8 bti = terrain->getBlendTextureIndex(i);
		try
		{
			img.load(bi.blendMapTextureFilename, ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
		} catch(Exception &e)
		{
			LOG("Error loading blendmap: " + bi.blendMapTextureFilename + " : " + e.getFullDescription());
			continue;
		}

		TerrainLayerBlendMap *blendmap = terrain->getLayerBlendMap(i);

		// resize that blending map so it will fit
		Ogre::uint32 blendmapSize = terrain->getLayerBlendMapSize();
		if (img.getWidth() != blendmapSize)
			img.resize(blendmapSize, blendmapSize);

		// now to the ugly part
		float* ptr = blendmap->getBlendPointer();
		for (Ogre::uint32 z = 0; z != blendmapSize; z++)
		{
			for (Ogre::uint32 x = 0; x != blendmapSize; x++)
			{
				Ogre::ColourValue c = img.getColourAt(x, z, 0);
				float alpha = bi.alpha;
				if      (bi.blendMode == 'R')
					*ptr++ = c.r * alpha;
				else if (bi.blendMode == 'G')
					*ptr++ = c.g * alpha;
				else if (bi.blendMode == 'B')
					*ptr++ = c.b * alpha;
				else if (bi.blendMode == 'A')
					*ptr++ = c.a * alpha;
			}
		}
		blendmap->dirty();
		blendmap->update();
	}

	if (debugBlendMaps)
	{
		for (int i = 1; i < layerCount; i++)
		{
			Ogre::TerrainLayerBlendMap* blendMap = terrain->getLayerBlendMap(i);
			Ogre::uint32 blendmapSize = terrain->getLayerBlendMapSize();
			Ogre::Image img;
			unsigned short *idata = OGRE_ALLOC_T(unsigned short, blendmapSize * blendmapSize, Ogre::MEMCATEGORY_RESOURCE);
			float scale = 65535.0f;
			for (unsigned int x = 0; x < blendmapSize; x++)
				for (unsigned int z = 0; z < blendmapSize; z++)
					idata[x + z * blendmapSize] = (unsigned short)(blendMap->getBlendValue(x, blendmapSize - z) * scale);
			img.loadDynamicImage((Ogre::uchar*)(idata), blendmapSize, blendmapSize, Ogre::PF_L16);
			std::string fileName = "blendmap_layer_" + Ogre::StringConverter::toString(i) + ".png";
			img.save(fileName);
			OGRE_FREE(idata, Ogre::MEMCATEGORY_RESOURCE);
		}
	}
}
Example #3
0
    void TerrainManager::initTerrainBlendMaps(Terrain* terrain,
                                              int cellX, int cellY,
                                              int fromX, int fromY, int size,
                                              const std::map<uint16_t, int>& indexes)
    {
        assert(terrain != NULL && "Must have valid terrain");
        assert(fromX >= 0 && fromY >= 0 &&
               "Can't get a terrain texture on terrain outside the current cell");
        assert(fromX+size <= ESM::Land::LAND_TEXTURE_SIZE &&
               fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
               "Can't get a terrain texture on terrain outside the current cell");

        //size must be a power of 2 as we do divisions with a power of 2 number
        //that need to result in an integer for correct splatting
        assert( (size & (size - 1)) == 0 && "Size must be a power of 2");

        const int blendMapSize = terrain->getLayerBlendMapSize();
        const int splatSize    = blendMapSize / size;

        //zero out every map
        std::map<uint16_t, int>::const_iterator iter;
        for ( iter = indexes.begin(); iter != indexes.end(); ++iter )
        {
            float* pBlend = terrain->getLayerBlendMap(iter->second)
                                   ->getBlendPointer();
            memset(pBlend, 0, sizeof(float) * blendMapSize * blendMapSize);
        }

        //covert the ltex data into a set of blend maps
        for ( int texY = fromY - 1; texY < fromY + size + 1; texY++ )
        {
            for ( int texX = fromX - 1; texX < fromX + size + 1; texX++ )
            {
                const uint16_t ltexIndex = getLtexIndexAt(cellX, cellY, texX, texY);

                //check if it is the base texture (which isn't in the map) and
                //if it is don't bother altering the blend map for it
                if ( indexes.find(ltexIndex) == indexes.end() )
                {
                    continue;
                }

                //while texX is the splat index relative to the entire cell,
                //relX is relative to the current segment we are splatting
                const int relX = texX - fromX;
                const int relY = texY - fromY;

                const int layerIndex = indexes.find(ltexIndex)->second;

                float* const pBlend = terrain->getLayerBlendMap(layerIndex)
                                             ->getBlendPointer();

                for ( int y = -1; y < splatSize + 1; y++ )
                {
                    for ( int x = -1; x < splatSize + 1; x++ )
                    {

                        //Note: Y is reversed
                        const int splatY = blendMapSize - 1 - relY * splatSize - y;
                        const int splatX = relX * splatSize + x;

                        if ( splatX >= 0 && splatX < blendMapSize &&
                             splatY >= 0 && splatY < blendMapSize )
                        {
                            const int index = (splatY)*blendMapSize + splatX;

                            if ( y >= 0 && y < splatSize &&
                                 x >= 0 && x < splatSize )
                            {
                                pBlend[index] = 1;
                            }
                            else
                            {
                                //this provides a transition shading but also
                                //rounds off the corners slightly
                                pBlend[index] = std::min(1.0f, pBlend[index] + 0.5f);
                            }
                        }

                    }
                }
            }
        }

        for ( int i = 1; i < terrain->getLayerCount(); i++ )
        {
             TerrainLayerBlendMap* blend = terrain->getLayerBlendMap(i);
             blend->dirty();
             blend->update();
        }

    }