00001
00002
00003 This file is subject to the terms and conditions of the GNU Lesser
00004 General Public License Version 2.1. See the file "COPYING" in the
00005 main directory of this archive for more details. */
00006
00007 #include "ps2gl/lighting.h"
00008 #include "ps2gl/glcontext.h"
00009 #include "ps2gl/matrix.h"
00010 #include "ps2gl/dlist.h"
00011 #include "ps2gl/material.h"
00012
00013
00014 * CImmLight
00015 */
00016
00017
00018
00019 int CImmLight::NumLights[3] = {0, 0, 0};
00020
00021 CImmLight::CImmLight( CGLContext &context, int lightNum )
00022 : CLight(context, lightNum),
00023 Ambient( 0.0f, 0.0f, 0.0f, 1.0f ),
00024 Diffuse( 0.0f, 0.0f, 0.0f, 0.0f ),
00025 Specular( 0.0f, 0.0f, 0.0f, 0.0f ),
00026 Position( 0.0f, 0.0f, 1.0f, 0.0f ),
00027 SpotDirection( 0.0f, 0.0f, -1.0f, 0.0f ),
00028 SpotCutoff(180.0f), SpotExponent(0.0f),
00029 ConstantAtten(1.0f), LinearAtten(0.0f), QuadAtten(0.0f),
00030 bIsEnabled(false),
00031 Type(kDirectional)
00032 {
00033 }
00034
00035 void
00036 CImmLight::CheckTypeChange( tLightType oldType )
00037 {
00038 if ( oldType != Type && bIsEnabled ) {
00039 CRendererManager &rm = GLContext.GetImmGeomManager().GetRendererManager();
00040 NumLights[oldType]--;
00041 NumLights[Type]++;
00042 rm.NumLightsChanged( oldType, NumLights[oldType] );
00043 rm.NumLightsChanged( Type, NumLights[Type] );
00044 }
00045 }
00046
00047 void
00048 CImmLight::SetEnabled( bool enabled )
00049 {
00050 if ( bIsEnabled != enabled ) {
00051 bIsEnabled = enabled;
00052 if (enabled) NumLights[Type]++;
00053 else NumLights[Type]--;
00054
00055 GLContext.GetImmLighting().SpecularChanged();
00056
00057 CRendererManager &rm = GLContext.GetImmGeomManager().GetRendererManager();
00058 rm.NumLightsChanged( Type, NumLights[Type] );
00059 }
00060 }
00061
00062 void
00063 CImmLight::SetSpecular( cpu_vec_xyzw specular )
00064 {
00065 cpu_vec_4 zero(0,0,0,0);
00066 if (specular == zero ^ Specular == zero) {
00067 Specular = specular;
00068 GLContext.GetImmLighting().SpecularChanged();
00069 }
00070 else
00071 Specular = specular;
00072
00073 TellRendererLightPropChanged();
00074 }
00075
00076 void
00077 CImmLight::SetPosition( cpu_vec_xyzw position )
00078 {
00079 CImmMatrixStack &modelView = GLContext.GetModelViewStack();
00080
00081 Position = modelView.GetTop() * position;
00082 TellRendererLightPropChanged();
00083
00084 tLightType oldType = Type;
00085 Type = (SpotCutoff == 180.0f) ? kPoint : kSpot;
00086 CheckTypeChange(oldType);
00087 }
00088
00089 void
00090 CImmLight::SetDirection( cpu_vec_xyzw direction )
00091 {
00092 CImmMatrixStack &modelView = GLContext.GetModelViewStack();
00093
00094 Position = modelView.GetTop() * direction.normalize();
00095 TellRendererLightPropChanged();
00096
00097 tLightType oldType = Type;
00098 Type = kDirectional;
00099 CheckTypeChange(oldType);
00100 }
00101
00102
00103 * CDListLight
00104 */
00105
00106 class CLightPropCmd : public CDListCmd {
00107 GLenum LightNum, Property;
00108 cpu_vec_xyzw Value;
00109 public:
00110 CLightPropCmd( GLenum lightNum, GLenum prop, cpu_vec_xyzw value )
00111 : LightNum(lightNum), Property(prop), Value(value) {}
00112 CDListCmd* Play() {
00113 glLightfv( LightNum, Property, reinterpret_cast<float*>(&Value) );
00114 return CDListCmd::GetNextCmd(this);
00115 }
00116 };
00117
00118 void
00119 CDListLight::SetAmbient( cpu_vec_xyzw ambient )
00120 {
00121 GLContext.GetDListManager().GetOpenDList()
00122 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_AMBIENT, ambient );
00123 TellRendererLightPropChanged();
00124 }
00125
00126 void
00127 CDListLight::SetDiffuse( cpu_vec_xyzw diffuse )
00128 {
00129 GLContext.GetDListManager().GetOpenDList()
00130 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_DIFFUSE, diffuse );
00131 TellRendererLightPropChanged();
00132 }
00133
00134 void
00135 CDListLight::SetSpecular( cpu_vec_xyzw specular )
00136 {
00137 GLContext.GetDListManager().GetOpenDList()
00138 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_SPECULAR, specular );
00139 TellRendererLightPropChanged();
00140 GLContext.SpecularEnabledChanged();
00141 }
00142
00143 void
00144 CDListLight::SetPosition( cpu_vec_xyzw position )
00145 {
00146 GLContext.GetDListManager().GetOpenDList()
00147 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_POSITION, position );
00148 TellRendererLightPropChanged();
00149 }
00150
00151 void
00152 CDListLight::SetDirection( cpu_vec_xyzw direction )
00153 {
00154 GLContext.GetDListManager().GetOpenDList()
00155 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_POSITION, direction );
00156 TellRendererLightPropChanged();
00157 }
00158
00159 void
00160 CDListLight::SetSpotDirection( cpu_vec_xyzw dir )
00161 {
00162 GLContext.GetDListManager().GetOpenDList()
00163 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_SPOT_DIRECTION, dir );
00164 TellRendererLightPropChanged();
00165 }
00166
00167 void
00168 CDListLight::SetSpotCutoff( float cutoff )
00169 {
00170 GLContext.GetDListManager().GetOpenDList()
00171 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_SPOT_CUTOFF, cpu_vec_xyzw(cutoff, 0, 0, 0) );
00172 TellRendererLightPropChanged();
00173 }
00174
00175 void
00176 CDListLight::SetSpotExponent( float exp )
00177 {
00178 GLContext.GetDListManager().GetOpenDList()
00179 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_AMBIENT, cpu_vec_xyzw(exp, 0, 0, 0) );
00180 TellRendererLightPropChanged();
00181 }
00182
00183 void
00184 CDListLight::SetConstantAtten( float atten )
00185 {
00186 GLContext.GetDListManager().GetOpenDList()
00187 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_CONSTANT_ATTENUATION, cpu_vec_xyzw(atten, 0, 0, 0) );
00188 TellRendererLightPropChanged();
00189 }
00190
00191 void
00192 CDListLight::SetLinearAtten( float atten )
00193 {
00194 GLContext.GetDListManager().GetOpenDList()
00195 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_LINEAR_ATTENUATION, cpu_vec_xyzw(atten, 0, 0, 0) );
00196 TellRendererLightPropChanged();
00197 }
00198
00199 void
00200 CDListLight::SetQuadAtten( float atten )
00201 {
00202 GLContext.GetDListManager().GetOpenDList()
00203 += CLightPropCmd( GL_LIGHT0 | LightNum, GL_QUADRATIC_ATTENUATION, cpu_vec_xyzw(atten, 0, 0, 0) );
00204 TellRendererLightPropChanged();
00205 }
00206
00207
00208 void
00209 CDListLight::SetEnabled( bool yesNo )
00210 {
00211 GLContext.GetDListManager().GetOpenDList()
00212 += CEnableCmd( GL_LIGHT0 | LightNum );
00213 TellRendererLightsEnabledChanged();
00214 }
00215
00216
00217
00218 * CLighting
00219 */
00220
00221 CImmLighting::CImmLighting( CGLContext &context )
00222 : CLighting(context),
00223 CurrentColor( 0.0f, 0.0f, 0.0f, 0.0f ),
00224 GlobalAmbient( 0.0f, 0.0f, 0.0f, 0.0f ),
00225 Light0(context, 0), Light1(context, 1), Light2(context, 2), Light3(context, 3),
00226 Light4(context, 4), Light5(context, 5), Light6(context, 6), Light7(context, 7),
00227 IsEnabled(false),
00228 NumLightsWithNonzeroSpecular(0)
00229 {
00230 Lights[0] = &Light0;
00231 Lights[1] = &Light1;
00232 Lights[2] = &Light2;
00233 Lights[3] = &Light3;
00234 Lights[4] = &Light4;
00235 Lights[5] = &Light5;
00236 Lights[6] = &Light6;
00237 Lights[7] = &Light7;
00238 }
00239
00240 void
00241 CImmLighting::SpecularChanged()
00242 {
00243 int count = 0;
00244 cpu_vec_4 zero(0,0,0,0);
00245 for ( int i = 0; i < 8; i++ )
00246 if ( Lights[i]->IsEnabled() && Lights[i]->GetSpecular() != zero )
00247 count++;
00248
00249 NumLightsWithNonzeroSpecular = count;
00250 if ( NumLightsWithNonzeroSpecular == 0 ) {
00251 GLContext.SpecularEnabledChanged();
00252 GLContext.GetImmGeomManager().GetRendererManager().SpecularEnabledChanged(false);
00253 }
00254 else
00255 GLContext.GetMaterialManager().GetImmMaterial().LightsHaveSpecular();
00256 }
00257
00258 void
00259 CImmLighting::MaterialHasSpecular()
00260 {
00261 if ( NumLightsWithNonzeroSpecular > 0 ) {
00262 GLContext.SpecularEnabledChanged();
00263 GLContext.GetImmGeomManager().GetRendererManager().SpecularEnabledChanged(true);
00264 }
00265 }
00266
00267
00268 CDListLighting::CDListLighting( CGLContext &context )
00269 : CLighting(context),
00270 Light0(context, 0), Light1(context, 1), Light2(context, 2), Light3(context, 3),
00271 Light4(context, 4), Light5(context, 5), Light6(context, 6), Light7(context, 7)
00272 {
00273 Lights[0] = &Light0;
00274 Lights[1] = &Light1;
00275 Lights[2] = &Light2;
00276 Lights[3] = &Light3;
00277 Lights[4] = &Light4;
00278 Lights[5] = &Light5;
00279 Lights[6] = &Light6;
00280 Lights[7] = &Light7;
00281 }
00282
00283 class CSetLightingEnabledCmd : public CDListCmd {
00284 bool IsEnabled;
00285 public:
00286 CSetLightingEnabledCmd( bool enabled ) : IsEnabled(enabled) {}
00287 CDListCmd* Play() {
00288 pGLContext->GetImmLighting().SetLightingEnabled(IsEnabled);
00289 return CDListCmd::GetNextCmd(this);
00290 }
00291 };
00292
00293 void
00294 CDListLighting::SetLightingEnabled( bool enabled )
00295 {
00296 GLContext.GetDListManager().GetOpenDList() += CSetLightingEnabledCmd(enabled);
00297 GLContext.LightingEnabledChanged();
00298 }
00299
00300 class CSetGlobalAmbientCmd : public CDListCmd {
00301 cpu_vec_xyzw Ambient;
00302 public:
00303 CSetGlobalAmbientCmd( cpu_vec_xyzw newAmb ) : Ambient(newAmb) {}
00304 CDListCmd* Play() {
00305 pGLContext->GetImmLighting().SetGlobalAmbient( Ambient );
00306 return CDListCmd::GetNextCmd(this);
00307 }
00308 };
00309
00310 void
00311 CDListLighting::SetGlobalAmbient( cpu_vec_xyzw newAmb )
00312 {
00313 GLContext.GetDListManager().GetOpenDList() += CSetGlobalAmbientCmd(newAmb);
00314 TellRendererLightPropChanged();
00315 }
00316
00317
00318 * gl interface
00319 */
00320
00321 void
00322 setPosition( CLight &light, float x, float y, float z, float w )
00323 {
00324 cpu_vec_xyzw pos(x, y, z, w);
00325 if ( w == 0.0f )
00326 light.SetDirection( pos );
00327 else
00328 light.SetPosition( pos );
00329 }
00330
00331 void glLightfv( GLenum lightNum,
00332 GLenum pname,
00333 const GLfloat *params )
00334 {
00335 CLighting& lighting = pGLContext->GetLighting();
00336 CLight& light = lighting.GetLight(0x7 & lightNum);
00337
00338 switch (pname) {
00339 case GL_AMBIENT:
00340 light.SetAmbient( cpu_vec_xyzw(params[0], params[1], params[2], params[3]) );
00341 break;
00342 case GL_DIFFUSE:
00343 light.SetDiffuse( cpu_vec_xyzw(params[0], params[1], params[2], params[3]) );
00344 break;
00345 case GL_SPECULAR:
00346 light.SetSpecular( cpu_vec_xyzw(params[0], params[1], params[2], params[3]) );
00347 break;
00348 case GL_POSITION:
00349 setPosition(light, params[0], params[1], params[2], params[3]);
00350 break;
00351 case GL_SPOT_DIRECTION:
00352 light.SetPosition( cpu_vec_xyzw(params[0], params[1], params[2], 0.0f).normalize() );
00353 break;
00354 case GL_SPOT_EXPONENT:
00355 light.SetSpotExponent( *params );
00356 break;
00357 case GL_SPOT_CUTOFF:
00358 light.SetSpotCutoff( *params );
00359 break;
00360 case GL_CONSTANT_ATTENUATION:
00361 light.SetConstantAtten( *params );
00362 break;
00363 case GL_LINEAR_ATTENUATION:
00364 light.SetLinearAtten( *params );
00365 break;
00366 case GL_QUADRATIC_ATTENUATION:
00367 light.SetQuadAtten( *params );
00368 break;
00369 default:
00370 mError("Shouldn't get here." );
00371 }
00372 }
00373
00374 void glLightf( GLenum lightNum, GLenum pname, GLfloat param )
00375 {
00376 CLighting& lighting = pGLContext->GetLighting();
00377 CLight& light = lighting.GetLight(0x7 & lightNum);
00378
00379 switch (pname) {
00380 case GL_SPOT_EXPONENT:
00381 light.SetSpotExponent( param );
00382 break;
00383 case GL_SPOT_CUTOFF:
00384 light.SetSpotCutoff( param );
00385 break;
00386 case GL_CONSTANT_ATTENUATION:
00387 light.SetConstantAtten( param );
00388 break;
00389 case GL_LINEAR_ATTENUATION:
00390 light.SetLinearAtten( param );
00391 break;
00392 case GL_QUADRATIC_ATTENUATION:
00393 light.SetQuadAtten( param );
00394 break;
00395 default:
00396 mError("Shouldn't get here." );
00397 }
00398 }
00399
00400 void glLightModelfv( GLenum pname, const GLfloat *params )
00401 {
00402 switch (pname) {
00403 case GL_LIGHT_MODEL_AMBIENT:
00404 pGLContext->GetLighting().SetGlobalAmbient( cpu_vec_xyzw( params[0],
00405 params[1],
00406 params[2],
00407 params[3] ) );
00408 break;
00409 case GL_LIGHT_MODEL_COLOR_CONTROL:
00410 if ( (int)*params == GL_SEPARATE_SPECULAR_COLOR ) {
00411 mNotImplemented( "separate specular color computation" );
00412 }
00413 break;
00414 case GL_LIGHT_MODEL_LOCAL_VIEWER:
00415 if ( (int)*params != 0 ) {
00416 mNotImplemented( "local viewer" );
00417 }
00418 break;
00419 case GL_LIGHT_MODEL_TWO_SIDE:
00420 if ( (int)*params != 0 ) {
00421 mNotImplemented( "two-sided lighting" );
00422 }
00423 break;
00424 default:
00425 mError("shouldn't get here");
00426 }
00427 }
00428
00429 void glLightModeli( GLenum pname, int param )
00430 {
00431 mNotImplemented( );
00432 }
00433
00434 void glGetLightfv( GLenum light, GLenum pname, float *params )
00435 {
00436 mNotImplemented( );
00437 }
00438
00439 void glFogf( GLenum pname, GLfloat param )
00440 {
00441 mNotImplemented( );
00442 }
00443
00444 void glFogfv( GLenum pname, const GLfloat *params )
00445 {
00446 mNotImplemented( );
00447 }