// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "std3d.h"
#include "nel/3d/texture_emboss.h"
namespace NL3D {
//***********************************************************************************************************
CTextureEmboss::CTextureEmboss() : _Ambient(CRGBA::Black),
_Diffuse(CRGBA::White),
_DisableSharing(false),
_SlopeFactor(1.f)
{
_LightDir.set(1.f, 1.f, 1.f);
_LightDir.normalize();
}
//***********************************************************************************************************
void CTextureEmboss::setHeightMap(ITexture *heightMap)
{
if (heightMap != _HeightMap)
{
_HeightMap = heightMap;
touch();
}
}
//***********************************************************************************************************
void CTextureEmboss::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
{
f.serialVersion(0);
ITexture::serial(f);
ITexture *tex = NULL;
if (f.isReading())
{
f.serialPolyPtr(tex);
_HeightMap = tex;
touch();
}
else
{
tex = _HeightMap;
f.serialPolyPtr(tex);
}
f.serial(_Ambient);
f.serial(_Diffuse);
f.serial(_LightDir);
f.serial(_DisableSharing);
}
//***********************************************************************************************************
bool CTextureEmboss::supportSharing() const
{
return !_DisableSharing && _HeightMap && _HeightMap->supportSharing();
}
//***********************************************************************************************************
std::string CTextureEmboss::getShareName() const
{
nlassert(supportSharing());
return "Emboss:" + _HeightMap->getShareName();
}
//***********************************************************************************************************
void CTextureEmboss::release()
{
ITexture::release();
if (_HeightMap != NULL)
{
if (_HeightMap->getReleasable())
{
_HeightMap->release();
}
}
}
//***********************************************************************************************************
void CTextureEmboss::doGenerate(bool /* async */)
{
if (!_HeightMap)
{
makeDummy();
return;
}
// generate the height map
_HeightMap->generate();
if (!_HeightMap->convertToType(CBitmap::RGBA))
{
makeDummy();
return;
}
CBitmap::resize(_HeightMap->getWidth(), _HeightMap->getHeight(), CBitmap::RGBA);
releaseMipMaps();
uint width = _HeightMap->getWidth();
uint height = _HeightMap->getHeight();
const CRGBA *src = (CRGBA *) &(_HeightMap->getPixels(0)[0]);
CRGBA *dest = (CRGBA *) &(getPixels(0)[0]);
CVector normal;
for (uint y = 0; y < height; ++y)
{
for (uint x = 0; x < width; ++x)
{
// get position of each adajacent pixel (sure, it can be optimized)
const CRGBA *pixelRight = (x != width - 1) ? (src + 1) : (src + 1 - width );
const CRGBA *pixelLeft = (x != 0) ? (src - 1) : (src + width - 1);
const CRGBA *pixelTop = (y != 0) ? (src - width) : (src + width * (height - 1));
const CRGBA *pixelBottom = (y != (height - 1)) ? (src + width) : (src - width * (height - 1));
normal.x = ((sint16) pixelRight->R - (sint16) pixelLeft->R) / 256.f;
normal.y = ((sint16) pixelTop->R - (sint16) pixelBottom->R) / 256.f;
normal.x *= _SlopeFactor;
NLMISC::clamp(normal.x, -1.f, 1.f);
normal.y *= _SlopeFactor;
NLMISC::clamp(normal.y, -1.f, 1.f);
normal.z = 1.f;
normal.normalize();
float colorValue = _LightDir * normal;
if (colorValue <= 0.f) colorValue = 0.f;
CRGBA diffuse;
*dest = _Ambient;
diffuse.modulateFromui(_Diffuse, (uint) (255.f * colorValue));
dest->add(*dest, diffuse);
dest->A = 255;
++ src;
++ dest;
}
}
if (_HeightMap->getReleasable())
{
_HeightMap->release();
}
}
}