1 /*
2  * Copyright (C) 1997-2005, R3vis Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18  *
19  * Original Contributor:
20  *   Wes Bethel, R3vis Corporation, Marin County, California
21  * Additional Contributor(s):
22  *
23  * The OpenRM project is located at http://openrm.sourceforge.net/.
24  */
25 /*
26  * $Id: rmlites.c,v 1.8 2005/08/06 15:30:39 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.8 $
29  * $Log: rmlites.c,v $
30  * Revision 1.8  2005/08/06 15:30:39  wes
31  * Reverted to RM_FALSE for localviewer in rmDefaultLighting. Turning off
32  * localviewer results in about a 50% increase in frame rate in one of
33  * our test cases.
34  *
35  * Revision 1.7  2005/06/26 18:51:23  wes
36  * In rmDefaultLighting, changed default setting of localview to RM_TRUE.
37  *
38  * Revision 1.6  2005/02/19 16:22:50  wes
39  * Distro sync and consolidation.
40  *
41  * Revision 1.5  2005/01/23 17:04:03  wes
42  * Copyright update to 2005.
43  *
44  * Revision 1.4  2004/03/10 01:45:10  wes
45  * Enabled use of global default spotlight exponent when a new light
46  * is created with rmLightNew.
47  *
48  * Revision 1.3  2004/01/16 16:45:12  wes
49  * Updated copyright line for 2004.
50  *
51  * Revision 1.2  2003/02/02 02:07:15  wes
52  * Updated copyright to 2003.
53  *
54  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
55  * Manual rebuild of rm150 repository.
56  *
57  * Revision 1.6  2003/01/16 22:21:17  wes
58  * Updated all source files to reflect new organization of header files:
59  * all header files formerly located in include/rmaux, include/rmi, include/rmv
60  * are now located in include/rm.
61  *
62  * Revision 1.5  2002/04/30 19:32:22  wes
63  * Updated copyright dates.
64  *
65  * Revision 1.4  2001/05/26 14:35:10  wes
66  * Doc mods.
67  *
68  * Revision 1.3  2001/03/31 17:12:38  wes
69  * v1.4.0-alpha-2 checkin.
70  *
71  * Revision 1.2  2000/04/20 16:29:47  wes
72  * Documentation additions/enhancements, some code rearragement.
73  *
74  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
75  * OpenRM 1.2 Checkin
76  *
77  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
78  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
79  *
80  */
81 
82 #include <rm/rm.h>
83 #include "rmprivat.h"
84 
85 /*
86  * ----------------------------------------------------
87  * @Name rmLightNew
88  @pstart
89  RMlight * rmLightNew (void)
90  @pend
91 
92  @astart
93  No arguments.
94  @aend
95 
96  @dstart
97 
98  Creates a new RMlight object, returning a handle to the new object to
99  the caller.
100 
101  The RMlight object is initialized with these values:
102 
103  1. Light type set to RM_LIGHT_DIRECTIONAL (see rmLightSetType).
104 
105  2. Light direction set to {0.0, 0.0, 1.0} (see rmLightSetXYZ).
106 
107  3. Light ambient, diffuse and specular colors set to {0, 0, 0},
108  {0.75, 0.75, 0.75} and {1.0, 1.0, 1.0} respectively (see
109  rmLightSetColor).
110 
111  4. Spotlight direction, and cutoff set to {0,0,-1} and 90 degrees,
112  respectively (see rmLightSetSpotDirection and rmLightSetSpotCutoff).
113  Note that these parameters have no meaning with a light source that
114  is not a spotlight.
115 
116  5. Light attenuation coefficients consist of a constant, linear and
117  quadratic terms. These are initialized to 1.0, 0.0 and 0.0,
118  respectively (see rmLightSetAttenuation).
119 
120  6. The light is enabled (see rmLightSetEnable) with RM_TRUE.
121 
122  Notes:
123 
124  The process of lighting in RM consists of a number of interrelated
125  factors. One is the presence of light sources in the scene as scene
126  parameters assigned to RMnodes. Another is the specification of a
127  light model, another scene parameter that specifies whether or not
128  lighting is two-sided (illumination of both front- and back-facing
129  polygons by ignoring the sign of the dot product of the surface
130  normal with the direction to/of the light source). Third, objects to
131  be illuminated must have 3D surface normals. The absence of any of
132  these three components will cause lighting/shading to "not work."
133 
134  Note that setting attributes in an RMlight does not change them in
135  the scene graph. They must be assigned as scene parameters to an
136  RMnode before they will be used in rendering (see
137  rmNodeSetSceneLight).
138 
139  @dend
140  * ----------------------------------------------------
141  */
142 RMlight *
rmLightNew(void)143 rmLightNew (void)
144 {
145     extern float      RM_DEFAULT_LIGHT_SPOT_CUTOFF;
146     extern float      RM_DEFAULT_LIGHT_CONSTANT_ATTENUATION;
147     extern float      RM_DEFAULT_LIGHT_LINEAR_ATTENUATION;
148     extern float      RM_DEFAULT_LIGHT_QUADRATIC_ATTENUATION;
149     extern float      RM_DEFAULT_LIGHT_SPOT_EXPONENT;
150     extern RMenum     RM_DEFAULT_LIGHT_ENABLE;
151     extern RMenum     RM_DEFAULT_LIGHT_TYPE;
152     extern RMvertex3D RM_DEFAULT_LIGHT_XYZ;
153     extern RMcolor4D  RM_DEFAULT_LIGHT_AMBIENT_COLOR;
154     extern RMcolor4D  RM_DEFAULT_LIGHT_DIFFUSE_COLOR;
155     extern RMcolor4D  RM_DEFAULT_LIGHT_SPECULAR_COLOR;
156     extern RMvertex3D RM_DEFAULT_LIGHT_SPOT_DIRECTION;
157 
158     RMlight *t = (RMlight *)malloc(sizeof(RMlight));
159 
160     if (t == NULL)
161 	return(NULL);
162 
163     memset(t, 0, sizeof(RMlight));
164 
165     /* assign default values */
166     rmLightSetType(t, RM_DEFAULT_LIGHT_TYPE);
167     rmLightSetXYZ(t, &RM_DEFAULT_LIGHT_XYZ);
168     rmLightSetColor(t, &RM_DEFAULT_LIGHT_AMBIENT_COLOR, &RM_DEFAULT_LIGHT_DIFFUSE_COLOR, &RM_DEFAULT_LIGHT_SPECULAR_COLOR);
169     rmLightSetSpotExponent(t, RM_DEFAULT_LIGHT_SPOT_EXPONENT);
170     rmLightSetSpotDirection(t, &RM_DEFAULT_LIGHT_SPOT_DIRECTION);
171     rmLightSetSpotCutoff(t, RM_DEFAULT_LIGHT_SPOT_CUTOFF);
172     rmLightSetAttenuation (t, RM_DEFAULT_LIGHT_CONSTANT_ATTENUATION, RM_DEFAULT_LIGHT_LINEAR_ATTENUATION, RM_DEFAULT_LIGHT_QUADRATIC_ATTENUATION);
173     rmLightSetEnable (t, RM_DEFAULT_LIGHT_ENABLE);
174 
175     return(t);
176 }
177 
178 
179 /*
180  * ----------------------------------------------------
181  * @Name rmLightDelete
182  @pstart
183  void rmLightDelete (RMlight *toDelete)
184  @pend
185 
186  @astart
187  RMlight *toDelete - a handle to an RMlight object.
188  @aend
189 
190  @dstart
191 
192  Frees resources associated with an RMlight object. This routine is
193  the opposite of rmLightNew().
194 
195  @dend
196  * ----------------------------------------------------
197  */
198 void
rmLightDelete(RMlight * t)199 rmLightDelete (RMlight *t)
200 {
201     if (RM_ASSERT(t, "rmLightDelete() error: the input RMlight is NULL.") == RM_WHACKED)
202 	return;
203 
204     free((void *)t);
205 }
206 
207 
208 /*
209  * ----------------------------------------------------
210  * @Name rmLightSetType
211  @pstart
212  RMenum rmLightSetType (RMlight *toModify,
213 	                RMenum newType)
214  @pend
215 
216  @astart
217  RMlight *toModify - a handle to an RMlight object (modified).
218 
219  RMenum newType - an RMenum value specifying the new light type for
220     the RMlight object. Must be one of RM_LIGHT_POINT,
221     RM_LIGHT_DIRECTIONAL, or RM_LIGHT_SPOT (input).
222  @aend
223 
224  @dstart
225 
226  RM light sources may be directional, spot or point light sources, and
227  this routine is used to set the type of an RMlight object to one of
228  those light source types. Returns RM_CHILL upon success, or
229  RM_WHACKED upon failure.
230 
231  RMlight objects represent light sources. Of the parameters in an
232  RMlight object, some are used regardless of light source type, while
233  others have meaning only for certain types of lights.
234 
235  The ambient, diffuse and specular color attributes are used by all
236  light source types (see rmLightSetColor). Also, the light attenuation
237  coefficients are used by all light source types (see
238  rmLightSetAttenuation).
239 
240  All light sources have a 3D coordinate associated with them, set with
241  rmLightSetXYZ. The position of Point light sources (RM_LIGHT_POINT)
242  and spotlight sources (RM_LIGHT_SPOT) is specified with
243  rmLightSetXYZ.  Directional light sources have their orientation
244  vector specified with rmLightSetXYZ.
245 
246  Note that setting attributes in an RMlight does not change them in
247  the scene graph. They must be assigned as scene parameters to an
248  RMnode before they will be used in rendering (see
249  rmNodeSetSceneLight).
250 
251  @dend
252  * ----------------------------------------------------
253  */
254 RMenum
rmLightSetType(RMlight * t,RMenum newType)255 rmLightSetType (RMlight *t,
256 	        RMenum newType)
257 {
258     if (RM_ASSERT(t, "rmLightSetType() error: the input RMlight is NULL") == RM_WHACKED)
259 	return(RM_WHACKED);
260 
261     if ((newType == RM_LIGHT_POINT) || (newType == RM_LIGHT_DIRECTIONAL) || (newType == RM_LIGHT_SPOT))
262     {
263 	t->ltype = newType;
264     }
265     else
266     {
267 	rmError("rmLightSetType() error: the newType enumerator is not one of RM_LIGHT_POINT, RM_LIGHT_DIRECTIONAL or RM_LIGHT_SPOT");
268 	return(RM_WHACKED);
269     }
270     return(RM_CHILL);
271 }
272 
273 
274 /*
275  * ----------------------------------------------------
276  * @Name rmLightGetType
277  @pstart
278  RMenum rmLightGetType (const RMlight *toQuery)
279  @pend
280 
281  @astart
282  const RMlight *toQuery - a handle to an RMlight object (input).
283  @aend
284 
285  @dstart
286 
287  Upon success, returns to the caller the RMlight light source type;
288  RM_LIGHT_POINT, RM_LIGHT_SPOT or RM_LIGHT_DIRECTIONAL. Otherwise,
289  returns RM_WHACKED.
290 
291  @dend
292  * ----------------------------------------------------
293  */
294 RMenum
rmLightGetType(const RMlight * t)295 rmLightGetType (const RMlight *t)
296 {
297     if (RM_ASSERT(t, "rmLightGetType() error: the input RMlight is NULL") == RM_WHACKED)
298 	return(RM_WHACKED);
299 
300     return(t->ltype);
301 }
302 
303 
304 /*
305  * ----------------------------------------------------
306  * @Name rmLightSetXYZ
307  @pstart
308  RMenum rmLightSetXYZ (RMlight *toModify,
309 	               const RMvertex3D *newXYZ)
310  @pend
311 
312  @astart
313  RMlight *toModify - a handle to an RMlight object (modified).
314 
315  const RMvertex3D *newXYZ - a handle to an RMvertex3D object (input).
316  @aend
317 
318  @dstart
319 
320  This routine is used to set the XYZ attribute of a light source
321  object, controlling the position of RM_LIGHT_POINT and RM_LIGHT_SPOT
322  sources, or the direction of RM_LIGHT_DIRECTIONAL objects. Copies
323  from the caller-supplied RMvertex3D object into the RMlight object.
324 
325  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
326 
327  Note that setting attributes in an RMlight does not change them in
328  the scene graph. They must be assigned as scene parameters to an
329  RMnode before they will be used in rendering (see
330  rmNodeSetSceneLight).
331 
332  @dend
333  * ----------------------------------------------------
334  */
335 RMenum
rmLightSetXYZ(RMlight * t,const RMvertex3D * newXYZ)336 rmLightSetXYZ (RMlight *t,
337 	       const RMvertex3D *newXYZ)
338 {
339     if ((RM_ASSERT(t, "rmLightSetXYZ() error: the input RMlight is NULL") == RM_WHACKED) ||
340 	(RM_ASSERT(newXYZ, "rmLightSetXYZ() error: the input newXYZ pointer is NULL") == RM_WHACKED))
341 	return(RM_WHACKED);
342 
343     t->lightXYZ = *newXYZ;
344 
345     return(RM_CHILL);
346 }
347 
348 
349 /*
350  * ----------------------------------------------------
351  * @Name rmLightGetXYZ
352  @pstart
353  RMenum rmLightGetXYZ (const RMlight *toQuery,
354 	               RMvertex3D *retXYZ)
355  @pend
356 
357  @astart
358  const RMlight *toQuery - a handle to an RMlight object (input).
359 
360  RMvertex3D *retXYZ - a handle to an RMvertex3D object (modified).
361  @aend
362 
363  @dstart
364 
365  Upon success, copies the light source's XYZ position/orientation
366  attribute from the RMlight object into the caller-supplied memory,
367  and returns RM_CHILL. Upon failure, returns RM_WHACKED.
368 
369  @dend
370  * ----------------------------------------------------
371  */
372 RMenum
rmLightGetXYZ(const RMlight * t,RMvertex3D * retXYZ)373 rmLightGetXYZ (const RMlight *t,
374 	       RMvertex3D *retXYZ)
375 {
376     if ((RM_ASSERT(t, "rmLightGetXYZ() error: the input RMlight is NULL") == RM_WHACKED) ||
377 	(RM_ASSERT(retXYZ, "rmLightGetXYZ() error: the input retXYZ pointer is NULL") == RM_WHACKED))
378 	return(RM_WHACKED);
379 
380     *retXYZ = t->lightXYZ;
381 
382     return(RM_CHILL);
383 }
384 
385 
386 /*
387  * ----------------------------------------------------
388  * @Name rmLightSetColor
389  @pstart
390  RMenum rmLightSetColor (RMlight *toModify,
391 		         const RMcolor4D *newAmbientColor,
392 			 const RMcolor4D *newDiffuseColor,
393 			 const RMcolor4D *newSpecularColor)
394  @pend
395 
396  @astart
397  RMlight *toModify - a handle to an RMlight object (modified).
398 
399  const RMcolor4D *newAmbientColor, *newDiffuseColor, *newSpecularColor
400     - handles to RMcolor4D objects specifying the RGBA colors for the
401     light source ambient, diffuse and specular light terms.  Use of
402     NULL for some or all terms is acceptable (input).
403  @aend
404 
405  @dstart
406 
407  In RM (and OpenGL), the final shade computed at a vertex is a
408  function of the vertex color, the current material properties and the
409  light source(s).  OpenGL uses a Phong-type shading model at each
410  vertex that computes the dot product of the surface normal at the
411  vertex (specified by the application) with the direction to each
412  light source (directional light sources require less work at this
413  stage than positional light sources).  This dot product to weight the
414  diffuse and specular reflectance terms of the shading equation.
415 
416  The Phong shading equation has terms for three types of light
417  reflectance: ambient, diffuse and specular. It is possible for
418  applications to specify the ambient, diffuse and specular terms
419  (colors) for both the light sources as well as the objects in the
420  scene to implement custom scenes like a yellow light shining on a
421  green ball.
422 
423  This routine is used to set the ambient, diffuse and specular color
424  terms for a specific light source.
425 
426  Note that the "global ambient light" level is set in the RMlightModel
427  object, not in the RMlight object (see rmLightModelNew).
428 
429  It is possible for applications to selectively modify a particular
430  reflectence color term - by specifying NULL for one of the input
431  color vectors, that term in the RMlight object is not modified. In
432  other words, only those non-NULL color terms are modified in the
433  RMlight object.
434 
435  Upon success, this routine copies from the caller-supplied RMcolor4D
436  objects into the RMlight object and returns RM_CHILL. Otherwise,
437  RM_WHACKED is returned.
438 
439  Note that setting attributes in an RMlight does not change them in
440  the scene graph. They must be assigned as scene parameters to an
441  RMnode before they will be used in rendering (see
442  rmNodeSetSceneLight).
443 
444  @dend
445  * ----------------------------------------------------
446  */
447 RMenum
rmLightSetColor(RMlight * t,const RMcolor4D * newAmbientColor,const RMcolor4D * newDiffuseColor,const RMcolor4D * newSpecularColor)448 rmLightSetColor (RMlight *t,
449 		 const RMcolor4D *newAmbientColor,
450 		 const RMcolor4D *newDiffuseColor,
451 		 const RMcolor4D *newSpecularColor)
452 {
453     if (RM_ASSERT(t, "rmLightSetAmbientColor() error: the input RMlight is NULL") == RM_WHACKED)
454 	return(RM_WHACKED);
455 
456     if (newAmbientColor != NULL)
457 	t->ambientLightColor = *newAmbientColor;
458 
459     if (newDiffuseColor != NULL)
460 	t->diffuseLightColor = *newDiffuseColor;
461 
462     if (newSpecularColor != NULL)
463 	t->specularLightColor = *newSpecularColor;
464 
465     return(RM_CHILL);
466 }
467 
468 
469 /*
470  * ----------------------------------------------------
471  * @Name rmLightGetColor
472  @pstart
473  RMenum rmLightGetColor (const RMlight *toQuery,
474 		         RMcolor4D *retAmbientColor,
475 			 RMcolor4D *retDiffuseColor,
476 			 RMcolor4D *retSpecularColor)
477  @pend
478 
479  @astart
480  const RMlight *toQuery - a handle to an RMlight object (input).
481 
482  RMcolor4D *retAmbientColor, *retDiffuseColor, *retSpecularColor -
483     handles to RMcolor4D objects (modified). Use of NULL for some or
484     all terms is acceptable (input).
485  @aend
486 
487  @dstart
488 
489  Use this routine to obtain one or more light source color vectors
490  from an RMlight object. Upon success, one or more color vectors is
491  copied from the RMlight object into caller-supplied memory, and
492  RM_CHILL is returned. Otherwise, RM_WHACKED is returned.
493 
494  @dend
495  * ----------------------------------------------------
496  */
497 RMenum
rmLightGetColor(const RMlight * t,RMcolor4D * retAmbientColor,RMcolor4D * retDiffuseColor,RMcolor4D * retSpecularColor)498 rmLightGetColor (const RMlight *t,
499 		 RMcolor4D *retAmbientColor,
500 		 RMcolor4D *retDiffuseColor,
501 		 RMcolor4D *retSpecularColor)
502 {
503     if (RM_ASSERT(t, "rmLightGetColor() error: the input RMlight is NULL") == RM_WHACKED)
504 	return(RM_WHACKED);
505 
506     if (retAmbientColor != NULL)
507 	*retAmbientColor = t->ambientLightColor;
508 
509     if (retDiffuseColor != NULL)
510 	*retDiffuseColor = t->diffuseLightColor;
511 
512     if (retSpecularColor != NULL)
513 	*retSpecularColor = t->specularLightColor;
514 
515     return(RM_CHILL);
516 }
517 
518 
519 /*
520  * ----------------------------------------------------
521  * @Name rmLightSetAttenuation
522  @pstart
523  RMenum rmLightSetAttenuation (RMlight *toModify,
524 		               float newConstantAttenuation,
525 			       float newLinearAttenuation,
526 			       float newQuadraticAttenuation)
527  @pend
528 
529  @astart
530  RMlight *toModify - a handle to an RMlight object (modified).
531 
532  float newConstantAttenuation, newLinearAttenuation,
533     newQuadraticAttenuation - floating point values specifying the
534     coefficients for constant, linear and quadratic light attenuation,
535     or decay, for an RMlight source (input).
536  @aend
537 
538  @dstart
539 
540  In the real world, light intensity decays as a function of distance
541  from the light source. The further away from the light source, the
542  weaker the light. The rate at which light decays is largely a
543  function of the medium through which the light energy passes. In a
544  vaccuum, like space, light decays slowly. In another medium, like
545  water, light decays more rapidly as the light energy is absorbed by
546  the participating medium.
547 
548  Applications have some measure of control over how light energy
549  decays as a function of distance from the light source through the
550  manipulation of "light attenuation factors." The equation used to
551  compute attenuation of light intensity at some point in space is:
552 
553  L = 1 / (Kc + Kl * d + Kq * d^2)
554 
555  where d is the distance to the light source.
556 
557  By default, that constant term (Kc) is set to 1.0, and the linear
558  (Kl) and quadratic (Kq) terms are set to zero; light energy does not
559  decay at all. Most OpenGL implementations are optimized for this
560  condition.
561 
562  Upon success, the three attenuation coefficients are copied into the
563  RMlight object, and RM_CHILL is returned. Otherwise, RM_WHACKED is
564  returned.
565 
566  Note that setting attributes in an RMlight does not change them in
567  the scene graph. They must be assigned as scene parameters to an
568  RMnode before they will be used in rendering (see
569  rmNodeSetSceneLight).
570 
571  @dend
572  * ----------------------------------------------------
573  */
574 RMenum
rmLightSetAttenuation(RMlight * t,float newConstantAttenuation,float newLinearAttenuation,float newQuadraticAttenuation)575 rmLightSetAttenuation (RMlight *t,
576 		       float newConstantAttenuation,
577 		       float newLinearAttenuation,
578 		       float newQuadraticAttenuation)
579 {
580     if (RM_ASSERT(t, "rmLightSetAttenuation() error: the input RMlight is NULL") == RM_WHACKED)
581 	return(RM_WHACKED);
582 
583     t->constantAttenuation = newConstantAttenuation;
584     t->linearAttenuation = newLinearAttenuation;
585     t->quadraticAttenuation = newQuadraticAttenuation;
586 
587     return(RM_CHILL);
588 }
589 
590 
591 /*
592  * ----------------------------------------------------
593  * @Name rmLightGetAttenuation
594  @pstart
595  RMenum rmLightGetAttenuation (const RMlight *toQuery,
596 		               float *retConstantAttenuation,
597 			       float *retLinearAttenuation,
598 			       float *retQuadraticAttenuation)
599  @pend
600 
601  @astart
602  const RMlight *toQuery - a handle to an RMlight object (input).
603 
604  float *retConstantAttenuation, *retLinearAttenuation,
605     *retQuadraticAttenuation - handle to caller-supplied floats
606     (modified).
607  @aend
608 
609  @dstart
610 
611  Upon success, copies the three light attenuation factors into
612  caller-supplied memory and returns RM_CHILL. Otherwise, RM_WHACKED is
613  returned.
614 
615  Note that all three input parameters must be non-NULL, otherwise an
616  error condition is produced.
617 
618  See rmLightSetAttenuation for more details about these attributes.
619 
620  @dend
621  * ----------------------------------------------------
622  */
623 RMenum
rmLightGetAttenuation(const RMlight * t,float * retConstantAttenuation,float * retLinearAttenuation,float * retQuadraticAttenuation)624 rmLightGetAttenuation (const RMlight *t,
625 		       float *retConstantAttenuation,
626 		       float *retLinearAttenuation,
627 		       float *retQuadraticAttenuation)
628 {
629     if ((RM_ASSERT(t, "rmLightGetAttenuation() error: the input RMlight is NULL") == RM_WHACKED) ||
630 	(RM_ASSERT(retConstantAttenuation, "rmLightGetAttenuation() error: the retConstantAttenuation pointer is NULL") == RM_WHACKED) ||
631 	(RM_ASSERT(retLinearAttenuation, "rmLightGetAttenuation() error: the retLinearAttenuation pointer is NULL") == RM_WHACKED) ||
632 	(RM_ASSERT(retQuadraticAttenuation, "rmLightGetAttenuation() error: the retQuadraticAttenuation pointer is NULL") == RM_WHACKED))
633 	return(RM_WHACKED);
634 
635     *retConstantAttenuation = t->constantAttenuation;
636     *retLinearAttenuation = t->linearAttenuation;
637     *retQuadraticAttenuation = t->quadraticAttenuation;
638 
639     return(RM_CHILL);
640 }
641 
642 
643 /*
644  * ----------------------------------------------------
645  * @Name rmLightSetEnable
646  @pstart
647  RMenum rmLightSetEnable (RMlight *toModify,
648 		          RMenum newValue)
649  @pend
650 
651  @astart
652  RMlight *toModify - a handle to an RMlight object (modified).
653 
654  RMenum newValue - an RMenum value, must be either RM_TRUE or
655     RM_FALSE.
656  @aend
657 
658  @dstart
659 
660  Light sources may be individually turned on or off by using this
661  routine. To turn a light on, use RM_TRUE, and to turn it off, use
662  RM_FALSE.
663 
664  Upon success, the newValue attribute is copied into the RMlight
665  object, and RM_CHILL is returned, otherwise RM_WHACKED is returned.
666 
667  Note that setting attributes in an RMlight does not change them in
668  the scene graph. They must be assigned as scene parameters to an
669  RMnode before they will be used in rendering (see
670  rmNodeSetSceneLight).
671 
672  @dend
673  * ----------------------------------------------------
674  */
675 RMenum
rmLightSetEnable(RMlight * t,RMenum newValue)676 rmLightSetEnable (RMlight *t,
677 		  RMenum newValue)
678 {
679     if (RM_ASSERT(t, "rmLightSetEnable() error: the input RMlight pointer is NULL.") == RM_WHACKED)
680 	return(RM_WHACKED);
681 
682     if (newValue == RM_TRUE || newValue == RM_FALSE)
683 	t->enabled = newValue;
684     else
685     {
686 	rmError("rmLightSetEnable() error: the input newValue enumerator is niether RM_TRUE nor RM_FALSE.");
687 	return(RM_WHACKED);
688     }
689     return(RM_CHILL);
690 }
691 
692 
693 /*
694  * ----------------------------------------------------
695  * @Name rmLightGetEnable
696  @pstart
697  RMenum rmLightGetEnable (const RMlight *toQuery)
698  @pend
699 
700  @astart
701  const RMlight *toQuery - a handle to an RMlight object (input).
702  @aend
703 
704  @dstart
705 
706  Upon success, returns to the caller either RM_TRUE or RM_FALSE,
707  indicating that the light source is either turned on or turned off,
708  respectively.  Otherwise, returns RM_WHACKED.
709 
710  @dend
711  * ----------------------------------------------------
712  */
713 RMenum
rmLightGetEnable(const RMlight * t)714 rmLightGetEnable (const RMlight *t)
715 {
716     if (RM_ASSERT(t, "rmLightGetEnable() error: the input RMlight object is NULL.") == RM_WHACKED)
717 	return(RM_WHACKED);
718 
719     return(t->enabled);
720 }
721 
722 
723 /*
724  * ----------------------------------------------------
725  * @Name  rmLightSetSpotDirection
726  @pstart
727  RMenum rmLightSetSpotDirection (RMlight *toModify,
728 			         const RMvertex3D *newSpotDirection)
729  @pend
730 
731  @astart
732  RMlight *toModify - a handle to an RMlight object (modified).
733 
734  const RMvertex3D *newSpotDirection - a handle to an RMvertex3D object
735     (input).
736  @aend
737 
738  @dstart
739 
740  Spotlight geometry is specified with both a position (rmLightSetXYZ)
741  and a direction (rmLightSetSpotDirection). This routine is used to
742  set the 3D orientation, or direction, of the spotlight light source.
743 
744  Upon success, this routine will copy the 3D vector from the
745  caller-supplied RMvertex3D object into the RMlight object and return
746  RM_CHILL. Upon failure, RM_WHACKED is returned.
747 
748  Note that setting attributes in an RMlight does not change them in
749  the scene graph. They must be assigned as scene parameters to an
750  RMnode before they will be used in rendering (see
751  rmNodeSetSceneLight).
752 
753  @dend
754  * ----------------------------------------------------
755  */
756 RMenum
rmLightSetSpotDirection(RMlight * t,const RMvertex3D * newSpotDirection)757 rmLightSetSpotDirection (RMlight *t,
758 			 const RMvertex3D *newSpotDirection)
759 {
760     if ((RM_ASSERT(t, "rmLightSetSpotDirection() error: the input RMlight is NULL") == RM_WHACKED) ||
761 	(RM_ASSERT(newSpotDirection, "rmLightSetSpotDirection() error: the input newSpotDirection pointer is NULL") == RM_WHACKED))
762 	return(RM_WHACKED);
763 
764     t->spotDirection = *newSpotDirection;
765 
766     return(RM_CHILL);
767 }
768 
769 
770 /*
771  * ----------------------------------------------------
772  * @Name rmLightGetSpotDirection
773  @pstart
774  RMenum rmLightGetSpotDirection (const RMlight *toModify,
775 			         RMvertex3D *retDirection)
776  @pend
777 
778  @astart
779  const RMlight *toModify - a handle to an RMlight object (input).
780 
781  RMvertex3D *retDirection - a handle to an RMvertex3D object
782     (modified, return).
783  @aend
784 
785  @dstart
786 
787  Spotlights are specified with both a position (rmLightSetXYZ) and a
788  direction (rmLightSetSpotDirection).  Use this routine to obtain the
789  direction vector of a spotlight source.
790 
791  Upon success, this routine copies the spotlight direction vector from
792  the RMlight object into the caller-supplied memory and returns
793  RM_CHILL. Upon failure, RM_WHACKED is returned.
794 
795  @dend
796  * ----------------------------------------------------
797  */
798 RMenum
rmLightGetSpotDirection(const RMlight * t,RMvertex3D * retDirection)799 rmLightGetSpotDirection (const RMlight *t,
800 			 RMvertex3D *retDirection)
801 {
802     if ((RM_ASSERT(t, "rmLightGetSpotDirection() error: the input RMlight is NULL") == RM_WHACKED) ||
803 	(RM_ASSERT(retDirection, "rmLightGetSpotDirection() error: the input retDirection pointer is NULL") == RM_WHACKED))
804 	return(RM_WHACKED);
805 
806     *retDirection = t->spotDirection;
807 
808     return(RM_CHILL);
809 }
810 
811 
812 /*
813  * ----------------------------------------------------
814  * @Name rmLightSetSpotCutoff
815  @pstart
816  RMenum rmLightSetSpotCutoff (RMlight *toModify,
817 		              float newValue)
818  @pend
819 
820  @astart
821  RMlight *toModify - a handle to an RMlight object (modified).
822 
823  float newValue - a floating point value in the range [0..90] (or the
824     special value of 180) specifying the spread angle of the
825     spotlight (input).
826  @aend
827 
828  @dstart
829 
830  The spotlight light source consists of a number of
831  parameters. Spotlight position is it's location in 3-space
832  (rmLightSetXYZ). The direction in which the spotlight is pointed is
833  it's orientation (rmLightSetSpotDirection). The light color consists
834  of ambient, diffuse and specular colors (rmLightSetColor). The rate
835  at which light decays as a function of distance from the light source
836  position is specified with constant, linear and quadratic
837  coefficients (rmLightSetAttenuation).  The spread angle of the
838  spotlight is a measure of the half-angle, in degrees, of the apex of
839  a cone formed by the spotlight, with the light positioned at the apex
840  of the cone and oriented towards the base of the cone
841  (rmLightSetSpotCutoff).  Finally, the rate at which light decays, or
842  falls off, as a function of distance from the vector formed by the
843  center of the spotlight cone (rmLightSetSpotExponent).
844 
845  This routine is used to set the value that controls the spread angle
846  of the spotlight light source. The value must be in the range 0 to
847  90, or the special value 180. This value specifies the half-angle of
848  the cone apex formed by the illumination volume of the spotlight
849  source. The spotlight source is positioned at the apex of this cone,
850  and shines in the direction of the base of the cone. The greater this
851  value, the larger the illumination volume. A value of 45 (degrees)
852  specifies an illumination volume with a cone apex of 90 degrees.
853 
854  The special value of 180.0 specifies a spotlight source that shines
855  in all directions.
856 
857  Upon success, the spotlight cutoff attribute of the RMlight object is
858  modified, and RM_CHILL is returned to the caller. Otherwise,
859  RM_WHACKED is returned.
860 
861  Note that setting attributes in an RMlight does not change them in
862  the scene graph. They must be assigned as scene parameters to an
863  RMnode before they will be used in rendering (see
864  rmNodeSetSceneLight).
865 
866  @dend
867  * ----------------------------------------------------
868  */
869 RMenum
rmLightSetSpotCutoff(RMlight * t,float newValue)870 rmLightSetSpotCutoff (RMlight *t,
871 		      float newValue)
872 {
873     if (RM_ASSERT(t, "rmLightSetSpotCutoff() error: the input RMlight is NULL") == RM_WHACKED)
874 	return(RM_WHACKED);
875 
876     t->spotCutoff = newValue;
877 
878     return(RM_CHILL);
879 }
880 
881 
882 /*
883  * ----------------------------------------------------
884  * @Name rmLightGetSpotCutoff
885  @pstart
886  RMenum rmLightGetSpotCutoff (const RMlight *toQuery,
887 		              float *retValue)
888  @pend
889 
890  @astart
891  const RMlight *toQuery - a handle to an RMlight object (input).
892 
893  float *retValue - a handle to a caller-supplied float (modified).
894  @aend
895 
896  @dstart
897 
898  Use this routine to obtain the spotlight cutoff value from an RMlight
899  object. Upon success, the spotlight cutoff value is copied into the
900  caller-supplied memory and RM_CHILL is returned. Otherwise,
901  RM_WHACKED is returned.
902 
903  See rmLightSetSpotCutoff for more details about the meaning of the
904  spotlight cutoff attribute.
905 
906  @dend
907  * ----------------------------------------------------
908  */
909 RMenum
rmLightGetSpotCutoff(const RMlight * t,float * retValue)910 rmLightGetSpotCutoff (const RMlight *t,
911 		      float *retValue)
912 {
913     if ((RM_ASSERT(t, "rmLightGetSpotCutoff() error: the input RMlight is NULL") == RM_WHACKED) ||
914 	(RM_ASSERT(retValue, "rmLightSetSpotCutoff() error: the return float pointer is NULL") == RM_WHACKED))
915 	return(RM_WHACKED);
916 
917     *retValue = t->spotCutoff;
918 
919     return(RM_CHILL);
920 }
921 
922 
923 /*
924  * ----------------------------------------------------
925  * @Name rmLightSetSpotExponent
926  @pstart
927  RMenum rmLightSetSpotExponent (RMlight *toModify,
928 		                float newValue)
929  @pend
930 
931  @astart
932  RMlight *toModify - a handle to an RMlight object (modified).
933 
934  float newValue - a non-negative floating point value (input).
935  @aend
936 
937  @dstart
938 
939  The spotlight light source consists of a number of
940  parameters. Spotlight position is it's location in 3-space
941  (rmLightSetXYZ). The direction in which the spotlight is pointed is
942  it's orientation (rmLightSetSpotDirection). The light color consists
943  of ambient, diffuse and specular colors (rmLightSetColor). The rate
944  at which light decays as a function of distance from the light source
945  position is specified with constant, linear and quadratic
946  coefficients (rmLightSetAttenuation).  The spread angle of the
947  spotlight is a measure of the half-angle, in degrees, of the apex of
948  a cone formed by the spotlight, with the light positioned at the apex
949  of the cone and oriented towards the base of the cone
950  (rmLightSetSpotCutoff).  Finally, the rate at which light decays, or
951  falls off, as a function of distance from the vector formed by the
952  center of the spotlight cone (rmLightSetSpotExponent).
953 
954  This routine is used to set the spotlight exponent value, or the rate
955  at which light decays as a function of distance from the center of
956  the illumination cone. By default, this parameter is set to zero,
957  indicating uniform light distribution (no decay) within the
958  illumination cone. Since this attribute specifies an exponent, light
959  decay falls off more rapidly as the value for this parameter
960  increases. Linear decay (inverse distance) is specified using a value
961  of 1.0 for this parameter; a value of 2.0 specifies that light falls
962  off as the inverse of the square of the distance to the center of the
963  illumination cone.
964 
965  Upon success, this routine copies the caller-supplied newValue
966  floating point value into the RMlight object's spotlight exponent
967  attribute and returns RM_CHILL, otherwise RM_WHACKED is returned.
968 
969  Note that setting attributes in an RMlight does not change them in
970  the scene graph. They must be assigned as scene parameters to an
971  RMnode before they will be used in rendering (see
972  rmNodeSetSceneLight).
973 
974  @dend
975  * ----------------------------------------------------
976  */
977 RMenum
rmLightSetSpotExponent(RMlight * t,float newValue)978 rmLightSetSpotExponent (RMlight *t,
979 		        float newValue)
980 {
981     if (RM_ASSERT(t, "rmLightSetSpotExponent() error: the input RMlight is NULL") == RM_WHACKED)
982 	return(RM_WHACKED);
983 
984     t->spotExponent = newValue;
985 
986     return(RM_CHILL);
987 }
988 
989 
990 /*
991  * ----------------------------------------------------
992  * @Name rmLightGetSpotExponent
993  @pstart
994  RMenum rmLightGetSpotExponent (const RMlight *toQuery,
995 		                float *retValue)
996  @pend
997 
998  @astart
999  const RMlight *toQuery - a handle to an RMlight object (input).
1000 
1001  float *retValue - a handle to a caller-supplied float (modified).
1002  @aend
1003 
1004  @dstart
1005 
1006  Use this routine to obtain the spotlight exponent attribute of an
1007  RMlight object. Upon success, the spotlight exponent attribute of the
1008  RMlight object is copied into caller-supplied memory, and RM_CHILL is
1009  returned. Otherwise, RM_WHACKED is returned.
1010 
1011  See rmLightSetSpotExponent for more details about the meaning and use
1012  of this attribute.
1013 
1014  @dend
1015  * ----------------------------------------------------
1016  */
1017 RMenum
rmLightGetSpotExponent(const RMlight * t,float * retValue)1018 rmLightGetSpotExponent (const RMlight *t,
1019 		        float *retValue)
1020 {
1021     if ((RM_ASSERT(t, "rmLightGetSpotExponent() error: the input RMlight is NULL") == RM_WHACKED) ||
1022 	(RM_ASSERT(retValue, "rmLightSetSpotExponent() error: the return float pointer is NULL") == RM_WHACKED))
1023 	return(RM_WHACKED);
1024 
1025     *retValue = t->spotExponent;
1026 
1027     return(RM_CHILL);
1028 }
1029 
1030 
1031 /*
1032  * ----------------------------------------------------
1033  * @Name rmLightModelNew
1034  @pstart
1035  RMlightModel * rmLightModelNew (void)
1036  @pend
1037 
1038  @astart
1039  No arguments.
1040  @aend
1041 
1042  @dstart
1043 
1044  Creates a new RMlightModel object, initializes it with default
1045  values, and returns to handle to the caller. NULL is returned upon
1046  failure.
1047 
1048  Lighting in RM (and OpenGL) is a function of light sources and the
1049  lighting environment. The RMlight objects contain information about
1050  the specific light sources, such as their position, light decay
1051  properties, color and so forth. The RMlightModel object controls
1052  global lighting parameters, including global ambient illumination,
1053  two-sided illumination control and selection of one of two algorithms
1054  used to compute specular reflection values.
1055 
1056  Global ambient illumination is the amount of light that is present
1057  everywhere in the scene, and represents the combination of overall
1058  composite luminance with the degree to which light is scattered.  By
1059  default, the ambient color assigned to the RMlightModel object is
1060  {0.,0.,0.}, indicating the absence of global ambient light. During
1061  shading, the global ambient term is applied to all vertices,
1062  regardless of the amount of ambient light specified in an RMlight
1063  object.  This term can be thought of as another independent light
1064  source in the scene (see rmLightModelSetAmbient).
1065 
1066  Two-sided illumination is used to create the effect of a
1067  bi-directional light source. By default, two-sided lighting is turned
1068  off (see rmLightModelSetTwoSided).
1069 
1070  Specular reflections take into account the surface normal, the
1071  direction to the light source from a vertex, and the direction to the
1072  viewer from the vertex. When the "local viewer" attribute is set to
1073  RM_TRUE, the direction to the viewer from each vertex is calculated
1074  during shading.  This results in more realistic shading, but at added
1075  computational expense. When set to RM_FALSE, the position of the
1076  viewer is fixed at (0,0,0) in eye coordinates (not world
1077  coordinates) for the purposes of shading.
1078 
1079  Note: OpenGL 1.2 adds a new term to the lighting model that can be
1080  used to control the computation specular reflection color. This
1081  feature has not yet been integrated into RM.
1082 
1083  Applications need to create both a light source and a light model in
1084  order for lighting to work properly.
1085 
1086  @dend
1087  * ----------------------------------------------------
1088  */
1089 RMlightModel  *
rmLightModelNew(void)1090 rmLightModelNew (void)
1091 {
1092     RMlightModel *t;
1093 
1094     t = (RMlightModel *)malloc(sizeof(RMlightModel));
1095 
1096     if (t == NULL)
1097     {
1098 	rmError("rmLightModelNew() error: unable to malloc a new RMlightModel object. ");
1099 	return(NULL);
1100     }
1101 
1102     memset(t, 0, sizeof(RMlightModel));
1103 
1104     /* default ambient is (0,0,0,0) */
1105     t->twoSideEnable = RM_FALSE;
1106     t->localViewerEnable = RM_FALSE;
1107 
1108     return(t);
1109 }
1110 
1111 
1112 /*
1113  * ----------------------------------------------------
1114  * @Name rmLightModelDelete
1115  @pstart
1116  RMenum rmLightModelDelete (RMlightModel *toDelete)
1117  @pend
1118 
1119  @astart
1120  RMlightModel *toDelete - a handle to an RMlightModel object to be
1121     deleted (modified).
1122  @aend
1123 
1124  @dstart
1125 
1126  Releases resources associated with an RMlightModel object. Returns
1127  RM_CHILL upon success, or RM_WHACKED upon failure. This routine is
1128  the opposite of rmLightModelNew.
1129 
1130  @dend
1131  * ----------------------------------------------------
1132  */
1133 RMenum
rmLightModelDelete(RMlightModel * toDelete)1134 rmLightModelDelete (RMlightModel *toDelete)
1135 {
1136     if (RM_ASSERT(toDelete, "rmLightModelDelete() error: the input RMlightModel pointer is NULL") == RM_WHACKED)
1137 	return(RM_WHACKED);
1138 
1139     free((void *)toDelete);
1140 
1141     return(RM_CHILL);
1142 }
1143 
1144 
1145 /*
1146  * ----------------------------------------------------
1147  * @Name rmLightModelSetAmbient
1148  @pstart
1149  RMenum rmLightModelSetAmbient (RMlightModel *toModify,
1150 			        const RMcolor4D *newAmbientColor)
1151  @pend
1152 
1153  @astart
1154  RMlightModel *toModify - a handle to an RMlightModel object (modified).
1155 
1156  const RMcolor4D *newAmbientColor - a handle to an RMcolor4D object
1157     (input).
1158  @aend
1159 
1160  @dstart
1161 
1162  Upon success, copies the contents of the RMcolor4D object to the
1163  RMlightModel object, and returns RM_CHILL. Otherwise, RM_WHACKED is
1164  returned.
1165 
1166  Color attributes are specified with floating point values in the
1167  range 0..1, where 0 is "off" and 1 is "on." The RMcolor4D object
1168  represents red, green, blue and alpha.
1169 
1170  See rmLightModelNew for more information about the global ambient
1171  light model attribute.
1172 
1173  Note that setting attributes in an RMlightModel does not change them
1174  in the scene graph. They must be assigned as scene parameters to an
1175  RMnode before they will be used in rendering (see
1176  rmNodeSetSceneLightModel).
1177 
1178  @dend
1179  * ----------------------------------------------------
1180  */
1181 RMenum
rmLightModelSetAmbient(RMlightModel * toModify,const RMcolor4D * newAmbientColor)1182 rmLightModelSetAmbient (RMlightModel *toModify,
1183 			const RMcolor4D *newAmbientColor)
1184 {
1185     if ((RM_ASSERT(toModify, "rmLightModelSetAmbient() error: the input RMlightModel pointer is NULL") == RM_WHACKED) ||
1186 	(RM_ASSERT(newAmbientColor, "rmLightModelSetAmbient() error: the input newAmbientColor pointer is NULL") == RM_WHACKED))
1187 	return(RM_WHACKED);
1188 
1189     toModify->globalAmbient = *newAmbientColor;
1190 
1191     return(RM_CHILL);
1192 }
1193 
1194 
1195 /*
1196  * ----------------------------------------------------
1197  * @Name rmLightModelGetAmbient
1198  @pstart
1199  RMenum rmLightModelGetAmbient (const RMlightModel *toQuery,
1200 			        RMcolor4D *retAmbientColor)
1201  @pend
1202 
1203  @astart
1204  const RMlightModel *toQuery - a handle to an RMlightModel object
1205     (input).
1206 
1207  RMcolor4D *retAmbientColor - a handle to an RMcolor4D object
1208     (modified).
1209  @aend
1210 
1211  @dstart
1212 
1213  Upon success, this routine will copy the global ambient light
1214  attribute from the RMlightModel object into the caller-supplied
1215  RMcolor4D object, and return RM_CHILL. Otherwise, RM_WHACKED is
1216  returned.
1217 
1218  See rmLightModelNew for more information about the global ambient
1219  light model attribute.
1220 
1221  @dend
1222  * ----------------------------------------------------
1223  */
1224 RMenum
rmLightModelGetAmbient(const RMlightModel * toQuery,RMcolor4D * retAmbientColor)1225 rmLightModelGetAmbient (const RMlightModel *toQuery,
1226 			RMcolor4D *retAmbientColor)
1227 {
1228     if ((RM_ASSERT(toQuery, "rmLightModelGetAmbient() error: the input RMlightModel pointer is NULL") == RM_WHACKED) ||
1229 	(RM_ASSERT(retAmbientColor, "rmLightModelGetAmbient() error: the input retAmbientColor pointer is NULL") == RM_WHACKED))
1230 	return(RM_WHACKED);
1231 
1232     *retAmbientColor = toQuery->globalAmbient;
1233 
1234     return(RM_CHILL);
1235 }
1236 
1237 
1238 /*
1239  * ----------------------------------------------------
1240  * @Name rmLightModelSetTwoSided
1241  @pstart
1242  RMenum rmLightModelSetTwoSided (RMlightModel *toModify,
1243 			         RMenum newValue)
1244  @pend
1245 
1246  @astart
1247  RMlightModel *toModify - a handle to an RMlightModel object
1248     (modified).
1249 
1250  RMenum newValue - an RMenum value, should be either RM_TRUE or
1251     RM_FALSE (input).
1252  @aend
1253 
1254  @dstart
1255 
1256  This routine sets the two-sided lighting attribute of an RMlightModel
1257  object. When RM_TRUE is specified, two-sided lighting is activitated
1258  for this light model. When set to RM_FALSE, two-sided lighting is
1259  disabled, and single-sided lighting takes effect.
1260 
1261  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1262 
1263  Note that setting attributes in an RMlightModel does not change them
1264  in the scene graph. They must be assigned as scene parameters to an
1265  RMnode before they will be used in rendering (see
1266  rmNodeSetSceneLightModel).
1267 
1268  @dend
1269  * ----------------------------------------------------
1270  */
1271 RMenum
rmLightModelSetTwoSided(RMlightModel * toModify,RMenum newValue)1272 rmLightModelSetTwoSided (RMlightModel *toModify,
1273 			 RMenum newValue)
1274 {
1275     if (RM_ASSERT(toModify, "rmLightModelSetTwoSided() error: the input RMlightModel pointer is NULL") == RM_WHACKED)
1276 	return(RM_WHACKED);
1277 
1278     if (newValue == RM_TRUE || newValue == RM_FALSE)
1279 	toModify->twoSideEnable = newValue;
1280     else
1281     {
1282 	rmWarning("rmLightModelTwoSided warning: the input RMenum is neither RM_TRUE nor RM_FALSE");
1283 	return(RM_WHACKED);
1284     }
1285 
1286     return(RM_CHILL);
1287 }
1288 
1289 
1290 /*
1291  * ----------------------------------------------------
1292  * @Name rmLightModelGetTwoSided
1293  @pstart
1294  RMenum rmLightModelGetTwoSided (const RMlightModel *toQuery)
1295  @pend
1296 
1297  @astart
1298  const RMlightModel *toQuery - a handle to an RMlightModel object
1299     (input).
1300  @aend
1301 
1302  @dstart
1303 
1304  Upon success, returns the setting of the two-sided lighting attribute
1305  of an RMlightModel object, either RM_TRUE or RM_FALSE. Otherwise,
1306  RM_WHACKED is returned.
1307 
1308  @dend
1309  * ----------------------------------------------------
1310  */
1311 RMenum
rmLightModelGetTwoSided(const RMlightModel * toQuery)1312 rmLightModelGetTwoSided (const RMlightModel *toQuery)
1313 {
1314     if (RM_ASSERT(toQuery, "rmLightModelGetTwoSided() error: the input RMlightModel pointer is NULL") == RM_WHACKED)
1315 	return(RM_WHACKED);
1316 
1317     return((RMenum)toQuery->twoSideEnable);
1318 }
1319 
1320 
1321 /*
1322  * ----------------------------------------------------
1323  * @Name rmLightModelSetLocalViewer
1324  @pstart
1325  RMenum rmLightModelSetLocalViewer (RMlightModel *toModify,
1326 			            RMenum newValue)
1327  @pend
1328 
1329  @astart
1330  RMlightModel *toModify - a handle to an RMlightModel object
1331     (modified).
1332 
1333  RMenum newValue - an RMenum value, must be either RM_TRUE or RM_FALSE
1334     (input).
1335  @aend
1336 
1337  @dstart
1338 
1339  This routine will set the "local viewer" attribute of the
1340  RMlightModel object to the value specified by the caller and return
1341  RM_CHILL upon success. Otherwise, RM_WHACKED is returned.
1342 
1343  See rmLightModelNew for more information about the "local viewer"
1344  attribute.
1345 
1346  Note that setting attributes in an RMlightModel does not change them
1347  in the scene graph. They must be assigned as scene parameters to an
1348  RMnode before they will be used in rendering (see
1349  rmNodeSetSceneLightModel).
1350 
1351  @dend
1352  * ----------------------------------------------------
1353  */
1354 RMenum
rmLightModelSetLocalViewer(RMlightModel * toModify,RMenum newValue)1355 rmLightModelSetLocalViewer (RMlightModel *toModify,
1356 			    RMenum newValue)
1357 {
1358     if (RM_ASSERT(toModify, "rmLightModelSetLocalViewer() error: the input RMlightModel pointer is NULL") == RM_WHACKED)
1359 	return(RM_WHACKED);
1360 
1361     if (newValue == RM_TRUE || newValue == RM_FALSE)
1362 	toModify->localViewerEnable = newValue;
1363     else
1364     {
1365 	rmError(" rmLightModelSetLocalViewer() error: the input enumerator is neither RM_TRUE nor RM_FALSE ");
1366 	return(RM_WHACKED);
1367     }
1368 
1369     return(RM_CHILL);
1370 }
1371 
1372 
1373 /*
1374  * ----------------------------------------------------
1375  * @Name rmLightModelGetLocalViewer
1376  @pstart
1377  RMenum rmLightModelGetLocalViewer (const RMlightModel *toQuery)
1378  @pend
1379 
1380  @astart
1381  const RMlightModel *toQuery - a handle to an RMlightModel object
1382     (input).
1383  @aend
1384 
1385  @dstart
1386 
1387  Upon success, returns the "local viewer" attribute of the
1388  RMlightModel object. Otherwise, RM_WHACKED is returned.
1389 
1390  See rmLightModelNew for more information about the "local viewer"
1391  attribute of the RMlightModel object.
1392 
1393  @dend
1394  * ----------------------------------------------------
1395  */
1396 RMenum
rmLightModelGetLocalViewer(const RMlightModel * toQuery)1397 rmLightModelGetLocalViewer (const RMlightModel *toQuery)
1398 {
1399     if (RM_ASSERT(toQuery, "rmLightModelGetLocalViewer() error: the input RMlightModel pointer is NULL") == RM_WHACKED)
1400 	return(RM_WHACKED);
1401 
1402     return((RMenum)toQuery->localViewerEnable);
1403 }
1404 
1405 
1406 /*
1407  * ----------------------------------------------------
1408  * @Name rmDefaultLighting
1409  @pstart
1410  RMenum rmDefaultLighting (RMnode *toModify)
1411  @pend
1412 
1413  @astart
1414  RMnode *toModify - a handle to an RMnode (modified).
1415  @aend
1416 
1417  @dstart
1418 
1419  This convenience routine is used to create a default set of lights
1420  and a default lighting model, and to assign them as scene parameters
1421  to an RMnode. The new lights and lighting model have effect over all
1422  children of the specified RMnode.
1423 
1424  The default lighting configuration consists of:
1425 
1426  1. One directional light source at 0,10,3 (overhead and slightly
1427     behind the viewer) with no ambient term, diffuse set to
1428     (0.7,0.7,0.7,1.0) and specular set to (0.5,0.5,0.5,1.0).  A second
1429     light source is available by uncommenting one line of code inside
1430     this routine.
1431 
1432  2. A light model with global ambient light set to (0.2,0.2,0.2,1.0),
1433     two-sided lighting disabled and disabling of "local viewer"
1434     specular reflection calculations.
1435 
1436  The net result is a lighting model that works reasonably well for
1437  most scenes both in terms of performance as well as illumination
1438  characteristics. While this convenience function is useful,
1439  developers are encouraged to examine this routine because it is a
1440  good example of how to create and modify light sources and light
1441  models, as well as assign them as scene parameters to an RMnode.
1442 
1443  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1444 
1445  @dend
1446  * ----------------------------------------------------
1447  */
1448 RMenum
rmDefaultLighting(RMnode * n)1449 rmDefaultLighting (RMnode *n)
1450 {
1451     /* light source zero is a from-the-top directional light */
1452     RMlight   *l0, *l1;
1453     RMcolor4D  diffuse = {0.7, 0.7, 0.7, 1.0};
1454     RMcolor4D  specular = {0.5, 0.5, 0.5, 1.0};
1455     RMcolor4D  diffuse2 = {0.3, 0.3, 0.5, 1.0};
1456     RMvertex3D pos2 = {0.0, -3.0, 1.0};
1457     RMvertex3D position = {0.0, 10.0, 3.0};
1458 
1459     l0 = rmLightNew();
1460     if (l0 == NULL)
1461 	return(RM_WHACKED);
1462 
1463     rmLightSetType(l0, RM_LIGHT_DIRECTIONAL);
1464     rmLightSetColor(l0, NULL, &diffuse, &specular);
1465     rmLightSetXYZ (l0, &position);
1466 
1467     /*
1468      * light source one is a from-the-bottom directional light with
1469      * reduced emphasis on diffuse and specular. the more dim
1470      * diffuse light is kind of blue.
1471      */
1472     l1 = rmLightNew();
1473     if (l1 == NULL)
1474 	return(RM_WHACKED);
1475 
1476     rmLightSetType(l1, RM_LIGHT_DIRECTIONAL);
1477     rmLightSetColor(l1, NULL, &diffuse2, &specular);
1478     rmLightSetXYZ(l1, &pos2);
1479 
1480     rmNodeSetSceneLight(n, RM_LIGHT0, l0);
1481     /*
1482      * uncomment the following line to add the second light source
1483      * into the scene. we leave it out by default for performance reasons,
1484      * but having it readily available for experimentation has proven useful.
1485      *
1486      * rmNodeSetSceneLight(n, RM_LIGHT1, l1);
1487      */
1488 
1489     /*
1490      * when the lights are added as scene parameters, RM makes a copy
1491      * of them, and we don't need our RMlight objects anymore, so we
1492      * need to delete them.
1493      */
1494 
1495     rmLightDelete(l0);
1496     rmLightDelete(l1);
1497 
1498     /* set up the light model/lighting environment */
1499     {
1500 	RMcolor4D     defAmbient =  {0.2, 0.2, 0.2, 1.0};
1501 	RMlightModel *lm = rmLightModelNew();
1502 
1503 	if (lm == NULL)
1504 	    return(RM_WHACKED);
1505 
1506 	rmLightModelSetAmbient(lm, &defAmbient);
1507 	rmLightModelSetTwoSided (lm, RM_FALSE);
1508 /*	rmLightModelSetLocalViewer(lm, RM_TRUE); */
1509 	rmLightModelSetLocalViewer(lm, RM_FALSE);
1510 	rmNodeSetSceneLightModel(n, lm);
1511 
1512 	rmLightModelDelete (lm);
1513     }
1514     return(RM_CHILL);
1515 }
1516 /* EOF */
1517