os/graphics/m3g/m3gcore11/src/m3g_light.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: Light implementation
    15 *
    16 */
    17 
    18 
    19 /*!
    20  * \internal
    21  * \file
    22  * \brief Light implementation
    23  */
    24 
    25 #ifndef M3G_CORE_INCLUDE
    26 #   error included by m3g_core.c; do not compile separately.
    27 #endif
    28 
    29 #include "m3g_light.h"
    30 #include "m3g_animationtrack.h"
    31 
    32 /*----------------------------------------------------------------------
    33  * Internal functions
    34  *--------------------------------------------------------------------*/
    35 
    36 /*!
    37  * \internal
    38  * \brief Overloaded Node method.
    39  *
    40  * Insert light to render queue.
    41  *
    42  * \param self Light object
    43  * \param toCamera transform to camera
    44  * \param alphaFactor total alpha factor
    45  * \param caller caller node
    46  * \param renderQueue RenderQueue
    47  *
    48  * \retval M3G_TRUE continue render setup
    49  * \retval M3G_FALSE abort render setup
    50  */
    51 static M3Gbool m3gLightSetupRender(Node *self,
    52                                    const Node *caller,
    53                                    SetupRenderState *s,
    54                                    RenderQueue *renderQueue)
    55 {
    56     M3G_UNREF(caller);
    57 
    58     if (renderQueue->lightManager != NULL) {
    59         Light *light = (Light *)self;
    60         
    61         if (self->enableBits & NODE_RENDER_BIT) {
    62             if (m3gInsertLight(renderQueue->lightManager,
    63                                light, &s->toCamera, M3G_INTERFACE(light)) == -1)
    64                 return M3G_FALSE;
    65         }
    66     }
    67 
    68     return M3G_TRUE;
    69 }
    70 
    71 /*!
    72  * \internal
    73  * \brief Overloaded Object3D method.
    74  *
    75  * \param property      animation property
    76  * \retval M3G_TRUE     property supported
    77  * \retval M3G_FALSE    property not supported
    78  */
    79 static M3Gbool m3gLightIsCompatible(M3Gint property)
    80 {
    81     switch (property) {
    82     case M3G_ANIM_COLOR:
    83     case M3G_ANIM_INTENSITY:
    84     case M3G_ANIM_SPOT_ANGLE:
    85     case M3G_ANIM_SPOT_EXPONENT:
    86         return M3G_TRUE;
    87     default:
    88         return m3gNodeIsCompatible(property);
    89     }
    90 }
    91 
    92 /*!
    93  * \internal
    94  * \brief Overloaded Object3D method.
    95  *
    96  * \param self          Light object
    97  * \param property      animation property
    98  * \param valueSize     size of value array
    99  * \param value         value array
   100  */
   101 static void m3gLightUpdateProperty(Object *self,
   102                                    M3Gint property,
   103                                    M3Gint valueSize,
   104                                    const M3Gfloat *value)
   105 {
   106     Light *light = (Light *)self;
   107     M3G_VALIDATE_OBJECT(light);
   108     M3G_ASSERT_PTR(value);
   109     
   110     switch (property) {
   111     case M3G_ANIM_COLOR:
   112         M3G_ASSERT(valueSize >= 3);
   113         light->color = m3gColor3f(value[0], value[1], value[2]);
   114         break;
   115     case M3G_ANIM_INTENSITY:
   116         M3G_ASSERT(valueSize >= 1);
   117         light->intensity = value[0];
   118         break;
   119     case M3G_ANIM_SPOT_ANGLE:
   120         M3G_ASSERT(valueSize >= 1);
   121         light->spotAngle = m3gClampFloat(value[0], 0.f, 90.f);
   122         break;
   123     case M3G_ANIM_SPOT_EXPONENT:
   124         M3G_ASSERT(valueSize >= 1);
   125         light->spotExponent = m3gClampFloat(value[0], 0.f, 128.f);
   126         break;
   127     default:
   128         m3gNodeUpdateProperty(self, property, valueSize, value);
   129     }
   130 }
   131 
   132 /*!
   133  * \internal
   134  * \brief Overloaded Object3D method.
   135  *
   136  * \param originalObj original Light object
   137  * \param cloneObj pointer to cloned Light object
   138  * \param pairs array for all object-duplicate pairs
   139  * \param numPairs number of pairs
   140  */
   141 static M3Gbool m3gLightDuplicate(const Object *originalObj,
   142                                  Object **cloneObj,
   143                                  Object **pairs,
   144                                  M3Gint *numPairs)
   145 {
   146     const Light *original = (const Light *) originalObj;
   147     Light *clone;
   148     M3G_ASSERT(*cloneObj == NULL); /* no derived classes for light */
   149     
   150     /* Create the clone object and exit on failure */
   151     
   152     clone = (Light *)m3gCreateLight(originalObj->interface);
   153     if (!clone) {
   154         return M3G_FALSE;
   155     }
   156     *cloneObj = (Object *)clone;
   157 
   158     /* Duplicate base class data */
   159     
   160     if (!m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs)) {
   161         return M3G_FALSE;
   162     }
   163 
   164     /* Duplicate own data */
   165     
   166 	clone->constantAttenuation = original->constantAttenuation;
   167 	clone->linearAttenuation = original->linearAttenuation;
   168 	clone->quadraticAttenuation = original->quadraticAttenuation;
   169 	clone->intensity = original->intensity;
   170 	clone->color = original->color;
   171 	clone->mode = original->mode;
   172     clone->spotAngle = original->spotAngle;
   173 	clone->spotExponent = original->spotExponent;
   174     
   175     return M3G_TRUE;
   176 }
   177 
   178 /*!
   179  * \internal
   180  * \brief Initializes a Light object. See specification
   181  * for default values.
   182  *
   183  * \param m3g           M3G interface
   184  * \param light         Light object
   185  */
   186 static void m3gInitLight(Interface *m3g, Light *light)
   187 {
   188 	/* Light is derived from node */
   189 	m3gInitNode(m3g, &light->node, M3G_CLASS_LIGHT);
   190 
   191 	light->constantAttenuation = 1.0f;
   192 	light->intensity = 1.0f;
   193 	light->color = 0x00ffffff;  /* Full white */
   194 	light->mode = M3G_DIRECTIONAL;
   195 	light->spotAngle = 45.0f;
   196 }
   197 
   198 /*!
   199  * \internal
   200  * \brief Applies this light to the current OpenGL context.
   201  *
   202  * \param self          Light object
   203  * \param glLight       OpenGL light index
   204  * \param pos           light position
   205  * \param spotDir       light direction
   206  */
   207 static void m3gApplyLight(const Light *self,
   208                           GLenum glLight,
   209                           const Vec4 *pos,
   210                           const Vec4 *spotDir)
   211 {
   212 	static const M3Gfloat BLACK[] = { 0.0f, 0.0f, 0.0f, 0.0f };
   213 	M3Gfloat light[4];
   214     
   215     M3G_ASSERT(m3gInRange(glLight, GL_LIGHT0, GL_LIGHT7));
   216     glEnable(glLight);
   217     
   218 	m3gFloatColor(self->color, self->intensity, light);
   219 
   220     /* Set light position */
   221     
   222     if (self->mode == M3G_DIRECTIONAL) {
   223         GLfloat temp[4];
   224         temp[0] = -spotDir->x;
   225         temp[1] = -spotDir->y;
   226         temp[2] = -spotDir->z;
   227         temp[3] = 0.0f;
   228         glLightfv(glLight, GL_POSITION, temp);
   229     }
   230     else {
   231         glLightfv(glLight, GL_POSITION, &pos->x);
   232         if (self->mode == M3G_SPOT) {
   233             glLightfv(glLight, GL_SPOT_DIRECTION, &spotDir->x);
   234         }
   235     }
   236 
   237     /* Set ambient, diffuse, and specular contributions */
   238     
   239 	if (self->mode == M3G_AMBIENT) {
   240 		glLightfv(glLight, GL_AMBIENT, light);
   241 		glLightfv(glLight, GL_DIFFUSE, BLACK);
   242 		glLightfv(glLight, GL_SPECULAR, BLACK);
   243 	}
   244 	else {
   245 		glLightfv(glLight, GL_AMBIENT, BLACK);
   246 		glLightfv(glLight, GL_DIFFUSE, light);
   247 		glLightfv(glLight, GL_SPECULAR, light);
   248 	}
   249 
   250     /* Set spot parameters */
   251     
   252 	if (self->mode == M3G_SPOT) {
   253 		glLightf(glLight, GL_SPOT_EXPONENT, self->spotExponent);
   254 		glLightf(glLight, GL_SPOT_CUTOFF, self->spotAngle);
   255 	}
   256 	else {
   257 		glLightf(glLight, GL_SPOT_CUTOFF, 180.0f);
   258 	}
   259 
   260     /* Set attenuation */
   261     
   262 	if (self->mode == M3G_OMNI || self->mode == M3G_SPOT) {
   263 		glLightf(glLight, GL_CONSTANT_ATTENUATION,  self->constantAttenuation);
   264 		glLightf(glLight, GL_LINEAR_ATTENUATION,    self->linearAttenuation);
   265 		glLightf(glLight, GL_QUADRATIC_ATTENUATION, self->quadraticAttenuation);
   266 	}
   267 	else if (self->mode == M3G_AMBIENT) {
   268 		glLightf(glLight, GL_CONSTANT_ATTENUATION,  1.0f);
   269 		glLightf(glLight, GL_LINEAR_ATTENUATION,    0.0f);
   270 		glLightf(glLight, GL_QUADRATIC_ATTENUATION, 0.0f);
   271 	}
   272 }
   273 
   274 /*----------------------------------------------------------------------
   275  * Virtual function table
   276  *--------------------------------------------------------------------*/
   277 
   278 static const NodeVFTable m3gvf_Light = {
   279     {
   280         {
   281             m3gObjectApplyAnimation,
   282             m3gLightIsCompatible,
   283             m3gLightUpdateProperty,
   284             m3gObjectDoGetReferences,
   285             m3gObjectFindID,
   286             m3gLightDuplicate,
   287             m3gDestroyNode
   288         }
   289     },
   290     m3gNodeAlign,
   291     NULL, /* pure virtual DoRender */
   292     m3gNodeGetBBox,
   293     m3gNodeRayIntersect,
   294     m3gLightSetupRender,
   295     m3gNodeUpdateDuplicateReferences,
   296     m3gNodeValidate
   297 };
   298 
   299 
   300 /*----------------------------------------------------------------------
   301  * Public API functions
   302  *--------------------------------------------------------------------*/
   303 
   304 /*!
   305  * \brief Creates a Light object.
   306  *
   307  * \param interface     M3G interface
   308  * \retval Light new Light object
   309  * \retval NULL Light creating failed
   310  */
   311 M3G_API M3GLight m3gCreateLight(M3GInterface interface)
   312 {
   313     Interface *m3g = (Interface *) interface;
   314     M3G_VALIDATE_INTERFACE(m3g);
   315 
   316 	{
   317 		Light *light =  m3gAllocZ(m3g, sizeof(Light));
   318 
   319         if (light != NULL) {
   320     		m3gInitLight(m3g, light);
   321         }
   322 
   323 		return (M3GLight) light;
   324 	}
   325 }
   326 
   327 /*!
   328  * \brief Set light intensity.
   329  *
   330  * \param handle        Light object
   331  * \param intensity     light intensity
   332  */
   333 M3G_API void m3gSetIntensity(M3GLight handle, M3Gfloat intensity)
   334 {
   335 	Light *light = (Light *) handle;
   336 	M3G_VALIDATE_OBJECT(light);
   337 	
   338 	light->intensity = intensity;
   339 }
   340 
   341 /*!
   342  * \brief Set light color as RGB.
   343  *
   344  * \param handle        Light object
   345  * \param rgb           light color as RGB
   346  */
   347 M3G_API void m3gSetLightColor(M3GLight handle, M3Guint rgb)
   348 {
   349 	Light *light = (Light *) handle;
   350 	M3G_VALIDATE_OBJECT(light);
   351 
   352 	light->color = rgb & M3G_RGB_MASK;
   353 }
   354 
   355 /*!
   356  * \brief Set light mode.
   357  *
   358  * \param handle        Light object
   359  * \param mode          light mode
   360  */
   361 M3G_API void m3gSetLightMode(M3GLight handle, M3Gint mode)
   362 {
   363 	Light *light = (Light *) handle;
   364 	M3G_VALIDATE_OBJECT(light);
   365 
   366 	if (mode < M3G_AMBIENT || mode > M3G_SPOT) {
   367     	m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
   368         return;
   369     }
   370 
   371 	light->mode = mode;
   372 }
   373 
   374 /*!
   375  * \brief Set light spot angle.
   376  *
   377  * \param handle        Light object
   378  * \param angle         spot angle
   379  */
   380 M3G_API void m3gSetSpotAngle(M3GLight handle, M3Gfloat angle)
   381 {
   382 	Light *light = (Light *) handle;
   383 	M3G_VALIDATE_OBJECT(light);
   384 
   385 	if (angle < 0.0f || angle > 90.f) {
   386     	m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
   387         return;
   388 	}
   389 
   390 	light->spotAngle = angle;
   391 }
   392 
   393 /*!
   394  * \brief Set light spot exponent.
   395  *
   396  * \param handle        Light object
   397  * \param exponent      spot exponent
   398  */
   399 M3G_API void m3gSetSpotExponent(M3GLight handle, M3Gfloat exponent)
   400 {
   401 	Light *light = (Light *) handle;
   402 	M3G_VALIDATE_OBJECT(light);
   403 
   404     if (exponent < 0.0f || exponent > 128.0f) {
   405     	m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
   406         return;
   407     }
   408 
   409     light->spotExponent = exponent;
   410 }
   411 
   412 /*!
   413  * \brief Set light attenuation factors.
   414  *
   415  * \param handle        Light object
   416  * \param constant      constant attenuation
   417  * \param linear        linear attenuation
   418  * \param quadratic     quadratic attenuation
   419  */
   420 M3G_API void m3gSetAttenuation(M3GLight handle,
   421                                M3Gfloat constant,
   422                                M3Gfloat linear,
   423                                M3Gfloat quadratic)
   424 {
   425 	Light *light = (Light *) handle;
   426 	M3G_VALIDATE_OBJECT(light);
   427 
   428     if (constant < 0.0f || linear < 0.0f || quadratic < 0.0f
   429         || (constant == 0.0f && linear == 0.0f && quadratic == 0.0f)) {
   430     	m3gRaiseError(M3G_INTERFACE(light), M3G_INVALID_VALUE);
   431         return;
   432     }
   433 
   434     light->constantAttenuation  = constant;
   435     light->linearAttenuation    = linear;
   436     light->quadraticAttenuation = quadratic;
   437 }
   438 
   439 /*!
   440  * \brief Get light intensity.
   441  *
   442  * \param handle        Light object
   443  * \return              light intensity
   444  */
   445 M3G_API M3Gfloat m3gGetIntensity(M3GLight handle)
   446 {
   447 	Light *light = (Light *) handle;
   448 	M3G_VALIDATE_OBJECT(light);
   449 
   450     return light->intensity;
   451 }
   452 
   453 /*!
   454  * \brief Get light color as RGB.
   455  *
   456  * \param handle        Light object
   457  * \return              light color as RGB
   458  */
   459 M3G_API M3Guint m3gGetLightColor(M3GLight handle)
   460 {
   461 	Light *light = (Light *) handle;
   462 	M3G_VALIDATE_OBJECT(light);
   463 
   464     return light->color;
   465 }
   466 
   467 /*!
   468  * \brief Get light mode.
   469  *
   470  * \param handle        Light object
   471  * \return              light mode
   472  */
   473 M3G_API M3Gint m3gGetLightMode(M3GLight handle)
   474 {
   475 	Light *light = (Light *) handle;
   476 	M3G_VALIDATE_OBJECT(light);
   477 
   478     return light->mode;
   479 }
   480 
   481 /*!
   482  * \brief Get light spot angle.
   483  *
   484  * \param handle        Light object
   485  * \return              light spot angle
   486  */
   487 M3G_API M3Gfloat m3gGetSpotAngle(M3GLight handle)
   488 {
   489 	Light *light = (Light *) handle;
   490 	M3G_VALIDATE_OBJECT(light);
   491 
   492     return light->spotAngle;
   493 }
   494 
   495 /*!
   496  * \brief Get light spot exponent.
   497  *
   498  * \param handle        Light object
   499  * \return              light spot exponent
   500  */
   501 M3G_API M3Gfloat m3gGetSpotExponent(M3GLight handle)
   502 {
   503 	Light *light = (Light *) handle;
   504 	M3G_VALIDATE_OBJECT(light);
   505 
   506     return light->spotExponent;
   507 }
   508 
   509 /*!
   510  * \brief Get light attenuation factor.
   511  *
   512  * \param handle        Light object
   513  * \param type          which factor to return
   514  *                      \arg M3G_GET_CONSTANT
   515  *                      \arg M3G_GET_LINEAR
   516  *                      \arg M3G_GET_QUADRATIC
   517  * \return              light attenuation factor
   518  */
   519 M3G_API M3Gfloat m3gGetAttenuation(M3GLight handle, M3Gint type)
   520 {
   521 	Light *light = (Light *) handle;
   522 	M3G_VALIDATE_OBJECT(light);
   523 
   524 	switch(type) {
   525 	case M3G_GET_CONSTANT:
   526 	    return light->constantAttenuation;
   527 	case M3G_GET_LINEAR:
   528     	return light->linearAttenuation;
   529     case M3G_GET_QUADRATIC:
   530 	default:
   531 	    return light->quadraticAttenuation;
   532 	}
   533 }
   534