[comp.sys.sgi] SGI lighting model?

phil@BRL.MIL (Phil Dykstra) (08/26/88)

Does anyone have some sample code that successfully uses the SGI
libgl lighting model?  Examples exist in the manual for mmode(),
but not for lmdef() and lmbind().  None of the demo programs that
I looked at use these routines either.  I made an attempt to use
them but with no results.  Anybody else?

- Phil
<phil@brl.mil>
uunet!brl-smoke!phil

woo@madonna.SGI.COM (Mason Woo) (08/31/88)

Here is some code which we use in the Advanced Graphics Course
to teach the use of lighting models on the IRIS.  A whole day is
devoted to the understanding of lighting.

This sample draws a flat-shaded, lighted sphere.  It demonstrates
lmdef(), lmbind(), mmode(), n3f(), and other subroutines.  It can
be easily (very easily) modified to draw a Gouraud-shaded sphere.

For more information on Customer Education courses, call 800-356-9492.

Mason Woo--Manager, Customer Education
Silicon Graphics

/*				liteye.c
 *	liteye.c displays the simplest lighting model.
 *      It displays a unit sphere with the light displayed from above.
 *      The lightmodel chooses the simplest model possible,
 *      with a local viewer, no attenuation or ambient light.
 *      The light source is differs from the default by placing
 *      the infinite light above the scene.
 *      The default material characteristics are selected.
 *	The light is attached to the eye.
 */

#include "gl.h"
#include "device.h"
#include "math.h"
#include "stdio.h"

#define SIMPLE_LM 1

float idmatrix[4][4] = {
	1.0, 0.0, 0.0, 0.0,
	0.0, 1.0, 0.0, 0.0,
	0.0, 0.0, 1.0, 0.0,
	0.0, 0.0, 0.0, 1.0};
	
main ()
{
    short attached;
    short value;
    int dev;
    int x, dx, oldx;            /*  mouse movement */

    float pt_sphere[40][40][3];	/*  endpoints of the sphere	*/
    int lat, longit;	        /*  number of longitude/latitude sides */

    dx = 0;
    attached = 1;
    initialize (&lat, &longit, pt_sphere);
 
    while (TRUE)
    {
	while (qtest() || !attached)
	{
	    dev = qread (&value);
	    if (dev == ESCKEY)
	    {
		gexit();
		exit(0);
	    }
	    else if (dev == REDRAW)
	    {
		reshapeviewport ();
		drawscene (dx, lat, longit, pt_sphere);
	    }
	    else if (dev == INPUTCHANGE)
		attached = value;	
	}   /*  end while qtest or not attached  */

	oldx = x;
	x = getvaluator (MOUSEX);
	if (getbutton (LEFTMOUSE))
	    dx = dx + (x - oldx);
	drawscene(dx, lat, longit, pt_sphere);

    }   /*  end while (TRUE)  */
}   /*  end main()  */

/*	The initialize subroutine positions the window and specifies
 *	its future constraints.  The program is in double buffer mode
 *	for animation and RGB mode for lighting.
 *	The sphere is initialized with a unique radius,
 * 	and the number of points in its longitude and latitude directions.
 *	mmode(MVIEWING) separates the projection and viewing matrices.
 *	The tables with the definitions for the lighting model,
 *	the light sources, and the material characteristics are loaded
 *	initlightdef().
 *	The simple lighting model defined in initlightdef is selected.
 */ 

initialize (lat, longit, pt_sphere)
int *lat, *longit;	/*  number of longitude/latitude sides */
float pt_sphere[40][40][3];	/*  endpoints of the sphere	*/
{
    int gid;
    float radius;	/*  radius of the sphere	*/

    prefposition (XMAXSCREEN/4, XMAXSCREEN*3/4, YMAXSCREEN/4, YMAXSCREEN*3/4);
    gid = winopen ("liteye");
    minsize (XMAXSCREEN/10, YMAXSCREEN/10);
    keepaspect (XMAXSCREEN, YMAXSCREEN);
    winconstraints();

    doublebuffer();
    /* lighting in RGB mode */
    RGBmode();
    gconfig();
 
    qdevice (ESCKEY);
    qdevice (REDRAW);
    qdevice (INPUTCHANGE);
    qenter (REDRAW, gid);

    lsetdepth (0x0, 0x7FFFFF);
    zbuffer (TRUE);

    radius = 1.0;
    *lat = 15;
    *longit = 20;
    initsphere (radius, *lat, *longit, pt_sphere);

    /* separate the viewing and projection matrices for lighting */
    mmode (MVIEWING);

    /* initialize the lighting definitions */
    /* load them into the lighting tables */
    initlightdef ();

    /* select (bind) the lighting model from the table */
    /* use for all scenes */
    lmbind(LMODEL, SIMPLE_LM);

    /* initialize the viewing stack before binding the light */
    /* load an identity matrix onto the viewing stack */
    /* since viewing and modeling commands multiplies what's on the stack */
    loadmatrix (idmatrix);
    polarview (5.0, 0, 0, 0);

    /* turn on the lights */
    /* select a light source from the table */
    /* attach a light source to the eye */
    /* select a light source BEFORE the viewing matrix has been loaded */
    /* the viewing matrix is reloaded in drawscene() */
    lmbind(LIGHT0, 1); 
}

/*	Initialize the lighting definitions for the 
 *	lighting model, the light sources and the material characteristics. 
 *	Load the definitions into the lighting tables.
 */
initlightdef () 
{
    /*  lighting model definitions */
    static float simple_lm[] = { AMBIENT, 0.0, 0.0, 0.0, 
 	           		 LOCALVIEWER, 1.0,
	                    	 LMNULL };
  
    /* light source definitions */
    static float top_lt[] = { POSITION, 0.0, 1.0, 0.30, 0.0,
  	         	      LMNULL };

    /* no material characteristic definitions */
    /* use the default lighting material */

    /* Select the simple lighting model */
    lmdef (DEFLMODEL, SIMPLE_LM, 0, simple_lm);

    /* load the light definition into the table of lights */
    /* lmdef (DEFLIGHT, 1, 0, NULL); */
    lmdef (DEFLIGHT, 1, 0, top_lt);

    /* load the material characteristics into material characteristics table */
    /* use the default material characteristics */
    lmdef (DEFMATERIAL, 1, 0, NULL);

}

/*	Draw the objects with fixed projection (perspective) and
 *	changing viewing (polarview) transformations.  dx is the
 *	amount the mouse has moved, and it changes the incidence angle.
 *
 *	Note that the routine is called from MVIEWING mode.
 *	The projection command automatically updates the projection matrix
 *	(as opposed to the viewing matrix).
 *	
 * 	The light is attached to the eye.
 */ 

drawscene (dx, lat, longit, pt_sphere)
int dx;
int lat, longit;	/*  number of longitude/latitude sides */
float pt_sphere[40][40][3];	/*  endpoints of the sphere	*/
{
    float aspect, x, y;

    x = (float) XMAXSCREEN;
    y = (float) YMAXSCREEN;
    aspect = x/y;

    czclear (0x00FFFFFF, 0x7FFFFF);

    /* select the current material characteristic from the table */
    lmbind(MATERIAL, 1);

    /* automatically loads the projection matrix 1-deep stack */
    perspective (450, aspect, 1.0, 10.0);
    
    /* initialize the viewing stack */
    /* load an identity matrix onto the viewing stack */
    /* since viewing and modeling commands multiplies what's on the stack */
    loadmatrix (idmatrix);
    polarview (5.0, 0, dx, 0);

    fillsphere_fn (lat, longit, pt_sphere);

    swapbuffers ();
}

/*
 *	This contains subroutines to render lighted geometric models.
 *      These objects have normals associated with them.
 *	The coordinates for these shapes must initially be calculated and
 *	loaded into arrays.
 *
 *	The subroutines in this file are:
 *	initsphere(rad, nlat, nlong, point)
 *	fillsphere_fn (nlat, nlong, point)
 *	fillsphere_Gn (nlat, nlong, point)
 */

/*	initsphere(rad, nlat, nlong, point)
 *	rad is the radius of the sphere.  
 *	nlat and nlong are the number of horizontal and vertical sides
 *	around the sphere.  point is an array of (x, y, z) vertices.
 *	This subroutine calculates and returns the coordinates for the
 *	vertices of a sphere which is centered at (0.0, 0.0, 0.0).
 *
 *	If there are more than 25 sides to the cross section, or 50 sides
 *	to the top view, the number of sides is limited.  
 *	See figure in manual for how these formulas were derived.
 */

initsphere (rad, nlat, nlong, point)
float rad;
int nlat;
int nlong;
float point[][40][3];
{
    int i, j, maxlat, maxlong;
    double pi, twopi, inclat, jj;
    double dval, magnitude;

    pi = 3.1415926535;
    twopi = pi * 2.0;
    maxlat = 40;
    maxlong = 40;
    
    if (nlat > maxlat)
        nlat = maxlat;
    if (nlong > maxlong)
        nlong = maxlong;
    inclat = pi/2.0;
    for (i = 0; i < nlat; i = i + 1)
    {		/*  go around cross section	*/
        magnitude = cos (inclat) * rad;
        dval = sin (inclat) * rad;
        
        for (j = 0; j < nlong; j = j + 1)
            point[i][j][1] = (float) dval;
        for (j = 0; j < nlong; j = j + 1)
        {	/*  go around top view		*/
            jj = (double) j;
            dval = cos (twopi*jj/nlong) * magnitude;
            point[i][j][0] = (float) dval;
            dval = sin (twopi*jj/nlong) * magnitude;
            point[i][j][2] = (float) dval;
        }

	inclat = inclat - (pi/(float) (nlat-1)); 
    }
}

/*	fillsphere_fn (nlat, nlong, point)
 *	Use initsphere() to initialize coordinates.
 *	nlat and nlong are the number of horizontal and vertical sides
 *	around the sphere.  point is an array of (x, y, z) vertices.
 *
 *	This subroutine draws a filled sphere with normals for 
 *	flat shading. One normal is sent down the pipe for each polygon.  
 *	First, except for boundaries, most of the sphere is drawn.  
 *	Then where the top view wraps around is drawn (between endpoints
 *	nlong-1 and 0).  Then where the cross section meets its beginning 
 *	is drawn (between endpoints nlat-1 and 0).  Finally, one final 
 *	rectangle is drawn, where both cross section and top view wrap 
 *	back to the 0 array element endpoint.
 */

fillsphere_fn (nlat, nlong, point)
int nlat, nlong;
float point[][40][3];
{
    int i, j;
    float normal[3];
  
    /*  draw most of the polygons in the sphere	*/    
    for ( i = 0; i < nlat-1; i = i+1 )
        for ( j = 0; j < nlong-1; j = j+1 )
        {
            /* find the normal as the average the four point vectors */
            normal[0] = ( point[i][j+1][0] + point[i+1][j+1][0] + 
                          point[i+1][j+1][0] + point[i][j][0] ) / 4.0;
            normal[1] = ( point[i][j+1][1] + point[i+1][j+1][1] + 
                          point[i+1][j+1][1] + point[i][j][1] ) / 4.0;
            normal[2] = ( point[i][j+1][2] + point[i+1][j+1][2] + 
                          point[i+1][j+1][2] + point[i][j][2] ) / 4.0;
            bgnpolygon();
            n3f( normal );
            v3f( point[i][j+1] );
            v3f( point[i+1][j+1] );
            v3f( point[i+1][j] );
            v3f( point[i][j] );
            endpolygon();
        }

    /*  once around the cross section, where the top view wraps around */
    for ( i = 0; i < nlat-1; i = i+1 )
    {
        /* find the normal as the average the four point vectors */
        normal[0] = ( point[i][0][0] + point[i+1][0][0] + 
                      point[i+1][nlong-1][0] + point[i][nlong-1][0] ) / 4.0;
        normal[1] = ( point[i][0][1] + point[i+1][0][1] + 
                      point[i+1][nlong-1][1] + point[i][nlong-1][1] ) / 4.0;
        normal[2] = ( point[i][0][2] + point[i+1][0][2] + 
                      point[i+1][nlong-1][2] + point[i][nlong-1][2] ) / 4.0;
        bgnpolygon();
        n3f( normal );
        v3f( point[i][0] );
        v3f( point[i+1][0] );
        v3f( point[i+1][nlong-1] );
        v3f( point[i][nlong-1] );
        endpolygon();
    }
}
 
/*	fillsphere_Gn (nlat, nlong, point)
 *	Use initsphere() to initialize coordinates.
 *	nlat and nlong are the number of horizontal and vertical sides
 *	around the sphere.  point is an array of (x, y, z) vertices.
 *
 *	This subroutine draws a filled sphere with normals for
 *	flat shading. One normal is sent down the pipe for each polygon.  
 *	First, except for boundaries, most of the sphere is drawn.  
 *	Then where the top view wraps around is drawn (between endpoints
 *	nlong-1 and 0).  Then where the cross section meets its beginning 
 *	is drawn (between endpoints nlat-1 and 0).  Finally, one final 
 *	rectangle is drawn, where both cross section and top view wrap 
 *	back to the 0 array element endpoint.
 */

fillsphere_Gn (nlat, nlong, point)
int nlat, nlong;
float point[][40][3];
{
    int i, j;
    float normal[3];
  
    /*  draw most of the polygons in the sphere	*/    
    for ( i = 0; i < nlat-1; i = i+1 )
        for ( j = 0; j < nlong-1; j = j+1 )
        {
            bgnpolygon();
            n3f( point[i][j+1] );
            v3f( point[i][j+1] );
            n3f( point[i+1][j+1] );
            v3f( point[i+1][j+1] );
            n3f( point[i+1][j] );
            v3f( point[i+1][j] );
            n3f( point[i][j] );
            v3f( point[i][j] );
            endpolygon();
        }

    /*  once around the cross section, where the top view wraps around */
    for ( i = 0; i < nlat-1; i = i+1 )
    {
        bgnpolygon();
        n3f( point[i][0] );
        v3f( point[i][0] );
        n3f( point[i+1][0] );
        v3f( point[i+1][0] );
        n3f( point[i+1][nlong-1] );
        v3f( point[i+1][nlong-1] );
        n3f( point[i][nlong-1] );
        v3f( point[i][nlong-1] );
        endpolygon();
    }
}
 
--
Mason Woo--Manager, Customer Education

Internet: woo@SGI.COM              UUCP: {ames,ucbvax,decwrl,sun}!sgi!woo

richr@ai.etl.army.mil (Richard Rosenthal) (08/31/88)

<This package filled by volume not weight.>

I tried to compile and load the provided code on 4D/60T ...

/usr/bin/ld:
Undefined:
lsetdepth
czclear
bgnpolygon
n3f
v3f
endpolygon
*** Error code 1

Stop.
$

Oh, well ...
-- 
Richard Rosenthal                 Internet:  richr@ai.etl.army.mil
Engineer Topographic Labs             UUCP:  ...!ames!ai.etl.army.mil!richr
Ft. Belvoir, VA 22060-5546          BITNET:  richr%ai.etl.army.mil@CUNYVM
+1 202 355 2830                      CSNET:  richr%ai.etl.army.mil@RELAY.CS.NET

woo@madonna.SGI.COM (Mason Woo) (09/01/88)

In article <181@ai.etl.army.mil>, richr@ai.etl.army.mil (Richard Rosenthal) writes:
> 
> I tried to compile and load the provided code on 4D/60T ...
> 
> /usr/bin/ld:
> Undefined:
> lsetdepth
> czclear
> bgnpolygon
> n3f
> v3f
> endpolygon
> *** Error code 1

Sorry, Richard, but I forgot to point out that you must be at Release 3.0,
which is standard on the IRIS 4D/GT.  If you are still at Release 2.0 on
the IRIS 4D, this code can be converted:

	change references from lsetdepth to setdepth
	change czclear to RGBcolor(), clear(), and zclear()
	change bgnpolygon(), n3f(), v3f(), endpolygon() to
		normal(), pmv(), normal(), pdr(), normal(), ..., pclos()

See the Graphics Library Guide for the precise syntax of these subroutines.

Thanks, again.

--
Mason Woo--Manager, Customer Education
Silicon Graphics Computer Systems
Internet: woo@SGI.COM              UUCP: {ames,ucbvax,decwrl,sun}!sgi!woo

archer@elysium.SGI.COM (Archer Sully) (09/01/88)

In article <181@ai.etl.army.mil>, richr@ai.etl.army.mil (Richard Rosenthal) writes:
> <This package filled by volume not weight.>
> 
> I tried to compile and load the provided code on 4D/60T ...
> 
> /usr/bin/ld:
> Undefined:
> lsetdepth
> czclear
> bgnpolygon
> n3f
> v3f
> endpolygon
> *** Error code 1
> 
> Stop.
> $
> 
> Oh, well ...
> -- 
> Richard Rosenthal                 Internet:  richr@ai.etl.army.mil

You were probably using 2.2.  The provided code is specific to 3.0.
It should be fairly easy to port, however.

lsetdepth is just like setdepth, except that it takes 24-bits of 
information instead of 16, so you can just use setdepth instead,
with the appropriate values.

czclear clears the zbuffer to a specified value, while clearing
the color planes at the same time, so just use a clear and zclear
instead.

n3f is just the 'normal' routine.

bgnpolygon(); v3f()...; endpolygon; is the new way of doing 
polygons in 3.0.  Each v3f command represents a vertex of the
polygon.  You should be able to use pmv and pdr to do the
same thing.

Archer Sully
archer@sgi.com

--