1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdopengl.h"
19 #include "driver_opengl.h"
20 #include "nel/3d/light.h"
30 namespace NLDRIVERGLES
{
32 namespace NLDRIVERGL
{
36 // ***************************************************************************
37 uint
CDriverGL::getMaxLight () const
39 H_AUTO_OGL(CDriverGL_getMaxLight
)
40 // return min(maxLight supported by openGL, MaxLight=8).
41 return _MaxDriverLight
;
45 // ***************************************************************************
46 void CDriverGL::setLight (uint8 num
, const CLight
& light
)
48 H_AUTO_OGL(CDriverGL_setLight
)
49 // bkup real light, for lightmap dynamic lighting purpose
53 // because the GL setup change, must dirt lightmap rendering
54 _LightMapDynamicLightDirty
= true;
57 setLightInternal(num
, light
);
61 // ***************************************************************************
62 void CDriverGL::setLightInternal(uint8 num
, const CLight
& light
)
64 H_AUTO_OGL(CDriverGL_setLightInternal
)
65 // Check light count is good
66 // nlassert (num<_MaxDriverLight);
69 if (num
<_MaxDriverLight
)
72 GLenum lightNum
=(GLenum
)(GL_LIGHT0
+num
);
75 CLight::TLightMode mode
=light
.getMode ();
80 // Set the ambiant color
82 CRGBA colorNeL
=light
.getAmbiant ();
83 colorGL
[0]=(float)colorNeL
.R
/255.f
;
84 colorGL
[1]=(float)colorNeL
.G
/255.f
;
85 colorGL
[2]=(float)colorNeL
.B
/255.f
;
87 glLightfv (lightNum
, GL_AMBIENT
, colorGL
);
89 // Set the diffuse color
90 colorNeL
=light
.getDiffuse ();
91 colorGL
[0]=(float)colorNeL
.R
/255.f
;
92 colorGL
[1]=(float)colorNeL
.G
/255.f
;
93 colorGL
[2]=(float)colorNeL
.B
/255.f
;
95 glLightfv (lightNum
, GL_DIFFUSE
, colorGL
);
97 // Set the specular color
98 colorNeL
=light
.getSpecular ();
99 // don't know why, but with ATI cards, specular of 0 causes incorrect rendering (random specular is added)
100 if (_Extensions
.ATITextureEnvCombine3
)
102 // special case for ATI (there will be some specular, but there's a bug otherwise)
103 colorGL
[0]=std::max(1.f
/ 1024.f
, (float)colorNeL
.R
/255.f
);
104 colorGL
[1]=std::max(1.f
/ 1024.f
, (float)colorNeL
.G
/255.f
);
105 colorGL
[2]=std::max(1.f
/ 1024.f
, (float)colorNeL
.B
/255.f
);
110 colorGL
[0]=(float)colorNeL
.R
/255.f
;
111 colorGL
[1]=(float)colorNeL
.G
/255.f
;
112 colorGL
[2]=(float)colorNeL
.B
/255.f
;
115 glLightfv (lightNum
, GL_SPECULAR
, colorGL
);
117 // Set light attenuation
118 glLightf (lightNum
, GL_CONSTANT_ATTENUATION
, light
.getConstantAttenuation());
119 glLightf (lightNum
, GL_LINEAR_ATTENUATION
, light
.getLinearAttenuation());
120 glLightf (lightNum
, GL_QUADRATIC_ATTENUATION
, light
.getQuadraticAttenuation());
123 if ((mode
==CLight::DirectionalLight
)||(mode
==CLight::SpotLight
))
125 // Get the direction of the light
126 _WorldLightDirection
[num
]=light
.getDirection ();
129 if (mode
!=CLight::DirectionalLight
)
131 // Get the position of the light
132 _WorldLightPos
[num
]=light
.getPosition ();
135 if (mode
==CLight::SpotLight
)
137 // Get the exponent of the spot
138 float exponent
=light
.getExponent ();
141 glLightf (lightNum
, GL_SPOT_EXPONENT
, exponent
);
143 // Get the cutoff of the spot
144 float cutoff
=180.f
*(light
.getCutoff ()/(float)NLMISC::Pi
);
147 glLightf (lightNum
, GL_SPOT_CUTOFF
, cutoff
);
151 // Disable spot properties
153 glLightf (lightNum
, GL_SPOT_CUTOFF
, 180.f
);
154 glLightf (lightNum
, GL_SPOT_EXPONENT
, 0.f
);
156 glLighti (lightNum
, GL_SPOT_CUTOFF
, 180);
157 glLighti (lightNum
, GL_SPOT_EXPONENT
, 0);
161 // Flag this light as dirt.
162 _LightDirty
[num
]= true;
164 // dirt the lightSetup and hence the render setup
165 _LightSetupDirty
= true;
166 _RenderSetupDirty
=true;
170 // ***************************************************************************
171 void CDriverGL::enableLight (uint8 num
, bool enable
)
173 H_AUTO_OGL(CDriverGL_enableLight
)
174 // User call => set the User flag
175 if(num
<_MaxDriverLight
)
177 _UserLightEnable
[num
]= enable
;
180 // enable the light in GL
181 enableLightInternal(num
, enable
);
183 // because the GL setup has changed, must dirt lightmap rendering
184 _LightMapDynamicLightDirty
= true;
188 // ***************************************************************************
189 void CDriverGL::enableLightInternal(uint8 num
, bool enable
)
191 H_AUTO_OGL(CDriverGL_enableLightInternal
)
192 // Check light count is good
193 // nlassert (num<_MaxDriverLight);
196 if (num
<_MaxDriverLight
)
198 _DriverGLStates
.enableLight(num
, enable
);
200 // If this light is dirty, and reenabled, then it must be refresh at next render => set the global flag.
201 if (enable
&& _LightDirty
[num
])
203 _LightSetupDirty
= true;
204 _RenderSetupDirty
= true;
210 // ***************************************************************************
212 void CDriverGL::setAmbientColor (CRGBA color
)
214 H_AUTO_OGL(CDriverGL_setAmbientColor
)
217 array
[0]=(float)color
.R
/255.f
;
218 array
[1]=(float)color
.G
/255.f
;
219 array
[2]=(float)color
.B
/255.f
;
223 glLightModelfv (GL_LIGHT_MODEL_AMBIENT
, array
);
227 // ***************************************************************************
228 void CDriverGL::cleanLightSetup ()
230 H_AUTO_OGL(CDriverGL_cleanLightSetup
)
232 nlassert (_LightSetupDirty
);
238 for (uint i
=0; i
<_MaxDriverLight
; i
++)
240 // Is this light enabled and dirty?
241 if (_DriverGLStates
.isLightEnabled(i
) && _LightDirty
[i
])
251 // Load the view matrix
252 glLoadMatrixf (_ViewMtx
.get());
255 // Light is directionnal ?
256 if (_LightMode
[i
]==(uint
)CLight::DirectionalLight
)
262 vectorGL
[0]=-_WorldLightDirection
[i
].x
;
263 vectorGL
[1]=-_WorldLightDirection
[i
].y
;
264 vectorGL
[2]=-_WorldLightDirection
[i
].z
;
268 glLightfv ((GLenum
)(GL_LIGHT0
+i
), (GLenum
)GL_POSITION
, vectorGL
);
272 if (_LightMode
[i
]==(uint
)CLight::SpotLight
)
278 vectorGL
[0]=_WorldLightDirection
[i
].x
;
279 vectorGL
[1]=_WorldLightDirection
[i
].y
;
280 vectorGL
[2]=_WorldLightDirection
[i
].z
;
283 glLightfv ((GLenum
)(GL_LIGHT0
+i
), (GLenum
)GL_SPOT_DIRECTION
, vectorGL
);
287 if (_LightMode
[i
]!=(uint
)CLight::DirectionalLight
)
293 // Must Substract CameraPos, because ViewMtx may not be the exact view.
294 vectorGL
[0]=_WorldLightPos
[i
].x
- _PZBCameraPos
.x
;
295 vectorGL
[1]=_WorldLightPos
[i
].y
- _PZBCameraPos
.y
;
296 vectorGL
[2]=_WorldLightPos
[i
].z
- _PZBCameraPos
.z
;
300 glLightfv ((GLenum
)(GL_LIGHT0
+i
), (GLenum
)GL_POSITION
, vectorGL
);
304 _LightDirty
[i
]= false;
313 _LightSetupDirty
=false;
317 // ***************************************************************************
318 void CDriverGL::setLightMapDynamicLight (bool enable
, const CLight
& light
)
320 H_AUTO_OGL(CDriverGL_setLightMapDynamicLight
)
321 // just store, for future setup in lightmap material rendering
322 _LightMapDynamicLightEnabled
= enable
;
323 _LightMapDynamicLight
= light
;
324 _LightMapDynamicLightDirty
= true;
328 // ***************************************************************************
329 void CDriverGL::setupLightMapDynamicLighting(bool enable
)
331 H_AUTO_OGL(CDriverGL_setupLightMapDynamicLighting
)
332 // start lightmap dynamic lighting
335 // disable all lights but the 0th.
336 for(uint i
=1;i
<_MaxDriverLight
;i
++)
337 enableLightInternal(i
, false);
339 // if the dynamic light is really enabled
340 if(_LightMapDynamicLightEnabled
)
342 // then setup and enable
343 setLightInternal(0, _LightMapDynamicLight
);
344 enableLightInternal(0, true);
346 // else just disable also the light 0
349 enableLightInternal(0, false);
352 // ok it has been setup
353 _LightMapDynamicLightDirty
= false;
355 // restore old lighting
358 // restore the light 0
359 setLightInternal(0, _UserLight0
);
361 // restore all standard light enable states
362 for(uint i
=0;i
<_MaxDriverLight
;i
++)
363 enableLightInternal(i
, _UserLightEnable
[i
]);
366 // in all case, must refresh render setup, cause lighting may be modified
367 refreshRenderSetup();