mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-17 06:38:43 +00:00
358 lines
9.4 KiB
C++
358 lines
9.4 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
#include "stdopengl.h"
|
|
|
|
#include "driver_opengl.h"
|
|
#include "nel/3d/light.h"
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
|
|
// ***************************************************************************
|
|
uint CDriverGL::getMaxLight () const
|
|
{
|
|
H_AUTO_OGL(CDriverGL_getMaxLight )
|
|
// return min(maxLight supported by openGL, MaxLight=8).
|
|
return _MaxDriverLight;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverGL::setLight (uint8 num, const CLight& light)
|
|
{
|
|
H_AUTO_OGL(CDriverGL_setLight )
|
|
// bkup real light, for lightmap dynamic lighting purpose
|
|
if(num==0)
|
|
{
|
|
_UserLight0= light;
|
|
// because the GL setup change, must dirt lightmap rendering
|
|
_LightMapDynamicLightDirty= true;
|
|
}
|
|
|
|
setLightInternal(num, light);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverGL::setLightInternal(uint8 num, const CLight& light)
|
|
{
|
|
H_AUTO_OGL(CDriverGL_setLightInternal)
|
|
// Check light count is good
|
|
// nlassert (num<_MaxDriverLight);
|
|
|
|
// Set the light
|
|
if (num<_MaxDriverLight)
|
|
{
|
|
// GL light number
|
|
GLenum lightNum=(GLenum)(GL_LIGHT0+num);
|
|
|
|
// Get light mode
|
|
CLight::TLightMode mode=light.getMode ();
|
|
|
|
// Copy the mode
|
|
_LightMode[num]=mode;
|
|
|
|
// Set the ambiant color
|
|
GLfloat colorGL[4];
|
|
CRGBA colorNeL=light.getAmbiant ();
|
|
colorGL[0]=(float)colorNeL.R/255.f;
|
|
colorGL[1]=(float)colorNeL.G/255.f;
|
|
colorGL[2]=(float)colorNeL.B/255.f;
|
|
colorGL[3]=1.f;
|
|
glLightfv (lightNum, GL_AMBIENT, colorGL);
|
|
|
|
// Set the diffuse color
|
|
colorNeL=light.getDiffuse ();
|
|
colorGL[0]=(float)colorNeL.R/255.f;
|
|
colorGL[1]=(float)colorNeL.G/255.f;
|
|
colorGL[2]=(float)colorNeL.B/255.f;
|
|
colorGL[3]=1.f;
|
|
glLightfv (lightNum, GL_DIFFUSE, colorGL);
|
|
|
|
// Set the specular color
|
|
colorNeL=light.getSpecular ();
|
|
// don't know why, but with ATI cards, specular of 0 causes incorrect rendering (random specular is added)
|
|
if (_Extensions.ATITextureEnvCombine3)
|
|
{
|
|
// special case for ATI (there will be some specular, but there's a bug otherwise)
|
|
colorGL[0]=std::max(1.f / 1024.f, (float)colorNeL.R/255.f);
|
|
colorGL[1]=std::max(1.f / 1024.f, (float)colorNeL.G/255.f);
|
|
colorGL[2]=std::max(1.f / 1024.f, (float)colorNeL.B/255.f);
|
|
colorGL[3]=1.f;
|
|
}
|
|
else
|
|
{
|
|
colorGL[0]=(float)colorNeL.R/255.f;
|
|
colorGL[1]=(float)colorNeL.G/255.f;
|
|
colorGL[2]=(float)colorNeL.B/255.f;
|
|
colorGL[3]=1.f;
|
|
}
|
|
glLightfv (lightNum, GL_SPECULAR, colorGL);
|
|
|
|
// Set light attenuation
|
|
glLightf (lightNum, GL_CONSTANT_ATTENUATION, light.getConstantAttenuation());
|
|
glLightf (lightNum, GL_LINEAR_ATTENUATION, light.getLinearAttenuation());
|
|
glLightf (lightNum, GL_QUADRATIC_ATTENUATION, light.getQuadraticAttenuation());
|
|
|
|
// Set the position
|
|
if ((mode==CLight::DirectionalLight)||(mode==CLight::SpotLight))
|
|
{
|
|
// Get the direction of the light
|
|
_WorldLightDirection[num]=light.getDirection ();
|
|
}
|
|
|
|
if (mode!=CLight::DirectionalLight)
|
|
{
|
|
// Get the position of the light
|
|
_WorldLightPos[num]=light.getPosition ();
|
|
}
|
|
|
|
if (mode==CLight::SpotLight)
|
|
{
|
|
// Get the exponent of the spot
|
|
float exponent=light.getExponent ();
|
|
|
|
// Set it
|
|
glLightf (lightNum, GL_SPOT_EXPONENT, exponent);
|
|
|
|
// Get the cutoff of the spot
|
|
float cutoff=180.f*(light.getCutoff ()/(float)NLMISC::Pi);
|
|
|
|
// Set it
|
|
glLightf (lightNum, GL_SPOT_CUTOFF, cutoff);
|
|
}
|
|
else
|
|
{
|
|
// Disactive spot properties
|
|
glLighti (lightNum, GL_SPOT_CUTOFF, 180);
|
|
glLighti (lightNum, GL_SPOT_EXPONENT, 0);
|
|
}
|
|
|
|
// Flag this light as dirt.
|
|
_LightDirty[num]= true;
|
|
|
|
// dirt the lightSetup and hence the render setup
|
|
_LightSetupDirty= true;
|
|
_RenderSetupDirty=true;
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CDriverGL::enableLight (uint8 num, bool enable)
|
|
{
|
|
H_AUTO_OGL(CDriverGL_enableLight )
|
|
// User call => set the User flag
|
|
// Geforce FX tmp fix
|
|
if (_Extensions.IsGeforceFXOrAbove && num >=3) return;
|
|
if(num<_MaxDriverLight)
|
|
{
|
|
_UserLightEnable[num]= enable;
|
|
}
|
|
|
|
// enable the light in GL
|
|
enableLightInternal(num, enable);
|
|
|
|
// because the GL setup has changed, must dirt lightmap rendering
|
|
_LightMapDynamicLightDirty= true;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverGL::enableLightInternal(uint8 num, bool enable)
|
|
{
|
|
H_AUTO_OGL(CDriverGL_enableLightInternal)
|
|
// Check light count is good
|
|
// nlassert (num<_MaxDriverLight);
|
|
|
|
// Enable glLight
|
|
if (num<_MaxDriverLight)
|
|
{
|
|
_DriverGLStates.enableLight(num, enable);
|
|
|
|
// If this light is dirty, and reenabled, then it must be refresh at next render => set the global flag.
|
|
if (enable && _LightDirty[num])
|
|
{
|
|
_LightSetupDirty= true;
|
|
_RenderSetupDirty= true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
void CDriverGL::setAmbientColor (CRGBA color)
|
|
{
|
|
H_AUTO_OGL(CDriverGL_setAmbientColor )
|
|
// Gl array
|
|
GLfloat array[4];
|
|
array[0]=(float)color.R/255.f;
|
|
array[1]=(float)color.G/255.f;
|
|
array[2]=(float)color.B/255.f;
|
|
array[3]=1.f;
|
|
|
|
// Set the color
|
|
glLightModelfv (GL_LIGHT_MODEL_AMBIENT, array);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverGL::cleanLightSetup ()
|
|
{
|
|
H_AUTO_OGL(CDriverGL_cleanLightSetup )
|
|
// Should be dirty
|
|
nlassert (_LightSetupDirty);
|
|
|
|
// First light
|
|
bool first=true;
|
|
|
|
// For each lights
|
|
for (uint i=0; i<_MaxDriverLight; i++)
|
|
{
|
|
// Is this light enabled and dirty?
|
|
if (_DriverGLStates.isLightEnabled(i) && _LightDirty[i])
|
|
{
|
|
// If first light
|
|
if (first)
|
|
{
|
|
first=false;
|
|
|
|
// Push the matrix
|
|
glPushMatrix ();
|
|
|
|
// Load the view matrix
|
|
glLoadMatrixf (_ViewMtx.get());
|
|
}
|
|
|
|
// Light is directionnal ?
|
|
if (_LightMode[i]==(uint)CLight::DirectionalLight)
|
|
{
|
|
// GL vector
|
|
GLfloat vectorGL[4];
|
|
|
|
// Set the GL array
|
|
vectorGL[0]=-_WorldLightDirection[i].x;
|
|
vectorGL[1]=-_WorldLightDirection[i].y;
|
|
vectorGL[2]=-_WorldLightDirection[i].z;
|
|
vectorGL[3]=0.f;
|
|
|
|
// Set it
|
|
glLightfv ((GLenum)(GL_LIGHT0+i), (GLenum)GL_POSITION, vectorGL);
|
|
}
|
|
|
|
// Spotlight ?
|
|
if (_LightMode[i]==(uint)CLight::SpotLight)
|
|
{
|
|
// GL vector
|
|
GLfloat vectorGL[4];
|
|
|
|
// Set the GL array
|
|
vectorGL[0]=_WorldLightDirection[i].x;
|
|
vectorGL[1]=_WorldLightDirection[i].y;
|
|
vectorGL[2]=_WorldLightDirection[i].z;
|
|
|
|
// Set it
|
|
glLightfv ((GLenum)(GL_LIGHT0+i), (GLenum)GL_SPOT_DIRECTION, vectorGL);
|
|
}
|
|
|
|
// Position
|
|
if (_LightMode[i]!=(uint)CLight::DirectionalLight)
|
|
{
|
|
// GL vector
|
|
GLfloat vectorGL[4];
|
|
|
|
// Set the GL array
|
|
// Must Substract CameraPos, because ViewMtx may not be the exact view.
|
|
vectorGL[0]=_WorldLightPos[i].x - _PZBCameraPos.x;
|
|
vectorGL[1]=_WorldLightPos[i].y - _PZBCameraPos.y;
|
|
vectorGL[2]=_WorldLightPos[i].z - _PZBCameraPos.z;
|
|
vectorGL[3]=1.f;
|
|
|
|
// Set it
|
|
glLightfv ((GLenum)(GL_LIGHT0+i), (GLenum)GL_POSITION, vectorGL);
|
|
}
|
|
|
|
// Cleaned!
|
|
_LightDirty[i]= false;
|
|
}
|
|
}
|
|
|
|
// Pop old matrix
|
|
if (!first)
|
|
glPopMatrix ();
|
|
|
|
// Clean flag
|
|
_LightSetupDirty=false;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverGL::setLightMapDynamicLight (bool enable, const CLight& light)
|
|
{
|
|
H_AUTO_OGL(CDriverGL_setLightMapDynamicLight )
|
|
// just store, for future setup in lightmap material rendering
|
|
_LightMapDynamicLightEnabled= enable;
|
|
_LightMapDynamicLight= light;
|
|
_LightMapDynamicLightDirty= true;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CDriverGL::setupLightMapDynamicLighting(bool enable)
|
|
{
|
|
H_AUTO_OGL(CDriverGL_setupLightMapDynamicLighting)
|
|
// start lightmap dynamic lighting
|
|
if(enable)
|
|
{
|
|
// disable all lights but the 0th.
|
|
for(uint i=1;i<_MaxDriverLight;i++)
|
|
enableLightInternal(i, false);
|
|
|
|
// if the dynamic light is really enabled
|
|
if(_LightMapDynamicLightEnabled)
|
|
{
|
|
// then setup and enable
|
|
setLightInternal(0, _LightMapDynamicLight);
|
|
enableLightInternal(0, true);
|
|
}
|
|
// else just disable also the light 0
|
|
else
|
|
{
|
|
enableLightInternal(0, false);
|
|
}
|
|
|
|
// ok it has been setup
|
|
_LightMapDynamicLightDirty= false;
|
|
}
|
|
// restore old lighting
|
|
else
|
|
{
|
|
// restore the light 0
|
|
setLightInternal(0, _UserLight0);
|
|
|
|
// restore all standard light enable states
|
|
for(uint i=0;i<_MaxDriverLight;i++)
|
|
enableLightInternal(i, _UserLightEnable[i]);
|
|
}
|
|
|
|
// in all case, must refresh render setup, cause lighting may be modified
|
|
refreshRenderSetup();
|
|
}
|
|
|
|
|
|
} // NL3D
|