ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/lib/mg/gl/mgglshade.c

This is mgglshade.c in view mode; [Download] [Up]

/* Copyright (c) 1992 The Geometry Center; University of Minnesota
   1300 South Second Street;  Minneapolis, MN  55454, USA;
   
This file is part of geomview/OOGL. geomview/OOGL is free software;
you can redistribute it and/or modify it only under the terms given in
the file COPYING, which you should have received along with this file.
This and other related software may be obtained via anonymous ftp from
geom.umn.edu; email: software@geom.umn.edu. */

/* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */

#include "mgP.h"
#include "mgglP.h"
#include "mgglshade.h"
#include <gl/gl.h>

#define MAXDEF 50

/* materialno, lightmodelno, and lightno between 1 and 65535 are
 * legal. p 9-9 GL PROG GUIDE (munzner 9/17/91)
 */
static int lightno = 1;
static float kd = 1.0;

mggl_appearance( struct mgastk *ma, int mask )
{
  Appearance *ap = &(ma->ap);

  if (mask & APF_TRANSP) {
    if (ap->flag & APF_TRANSP) {
      zwritemask(0);
      blendfunction(BF_SA, BF_MSA);
    } else {
      zwritemask(~0);
      blendfunction(BF_ONE, BF_ZERO);
    }
  }

  if (mask & APF_LINEWIDTH) {
    linewidth(ap->linewidth);
    _mgc->has &= ~HAS_POINT;
  }

  if (mask & APF_SHADING) {
    if(!IS_SHADED(ap->shading) || ma->shader != NULL) {
	/* switch to constant shading by unbinding the lmodel */
	lmbind(LMODEL, 0);
	lmbind(MATERIAL, 0);
	_mgglc->d4f = c4f;
	_mgglc->lmcolor = LMC_COLOR;
	shademodel(IS_SMOOTH(ap->shading) ? GOURAUD : FLAT );
	ma->useshader = (ma->shader != NULL) && IS_SHADED(ap->shading);
    }
    else {
	/* turn shading on */
	shademodel( IS_SMOOTH(ap->shading) ? GOURAUD : FLAT );
	if (ap->lighting->valid)
	    lmbind(LMODEL, ma->light_seq);
	lmbind(MATERIAL, ma->mat_seq);
	_mgglc->d4f = mggl_d4f;
	_mgglc->lmcolor = LMC_DIFFUSE;
	ma->useshader = 0;
    }
  }

  if(mask & APF_EVERT) {
    /*
     * Do automatic normal-flipping if requested.
     */
    _mgglc->n3f = (ap->flag & APF_EVERT) ?
			(void (*)())mggl_n3fevert : (void (*)())n3f;
  }
 
  /*
   * No GL calls are needed for the following attributes because
   * they are always interpreted at draw-time:
   *		APF_FACEDRAW
   *		APF_EDGEDRAW
   *		APF_NORMSCALE
   */

}

/*-----------------------------------------------------------------------
 * Function:	mggl_material
 * Description:	bind a material. define it if it's not yet defined.
 * Args:	*mat: Material to bind.
 *		mask: Bitmask telling which material fields are valid.
 *		      Passed into mggl_materialdef.
 * Returns:	
 * Author:	munzner
 * Date:	Wed Oct 16 16:06:47 1991
 * Notes:	We must reset the "current GL color" after binding a
 *		material.
 *		We want color calls to change the *diffuse* color when
 *		we're in shading mode. Thus we call lmcolor(LMC_DIFFUSE).
 *		We also must keep track of the diffuse coefficient
 *		for use in mggl_d[3,4]f, our wrapper for color calls.
 *		C3f or c4f should never be called directly.
 *		mg draw routines are responsible for establishing the
 * 		correct drawing color.
 */
void
mggl_material(register struct mgastk *astk, int mask)
{
    float surface[MAXDEF];
    register float *f;
    Material *mat = &astk->mat;
    static float lmnull = LMNULL;

    mask &= mat->valid;
    if (mask & MTF_Kd)
	kd = mat->kd;

    if((mask & (MTF_EMISSION|MTF_DIFFUSE|MTF_AMBIENT|MTF_SPECULAR
		|MTF_SHININESS|MTF_Kd|MTF_Ka|MTF_Ks|MTF_ALPHA)) == 0)
	return;		/* No GL changes to make. */

    if(astk->next && astk->next->mat_seq == astk->mat_seq) {
	/*
	 * Fresh material needed.  Erase any previous GL definition.
	 * We'll need to load all valid fields to initialize it.
	 */
	astk->mat_seq++;
	lmdef(DEFMATERIAL, astk->mat_seq, 0, &lmnull);
	lmbind(MATERIAL, astk->mat_seq);
	mask = mat->valid;
    }

	/* Build material definition */
    f = surface;

    if( mask & MTF_EMISSION) {
	*f++ = EMISSION;
	*f++ = mat->emission.r;
	*f++ = mat->emission.g;
	*f++ = mat->emission.b;
    }

    if( mask & (MTF_Ka | MTF_AMBIENT)) {
	*f++ = AMBIENT;
	*f++ = mat->ka * mat->ambient.r;
	*f++ = mat->ka * mat->ambient.g;
	*f++ = mat->ka * mat->ambient.b;
    }
    if( mask & (MTF_Kd | MTF_DIFFUSE)) {
	*f++ = DIFFUSE;
	*f++ = mat->kd * mat->diffuse.r;
	*f++ = mat->kd * mat->diffuse.g;
	*f++ = mat->kd * mat->diffuse.b;
    }
    if( mask & (MTF_Ks | MTF_SPECULAR | MTF_SHININESS)) {
	*f++ = SPECULAR;
	*f++ = mat->ks * mat->specular.r;
	*f++ = mat->ks * mat->specular.g;
	*f++ = mat->ks * mat->specular.b;
	*f++ = SHININESS;
	*f++ = mat->shininess;
    }
    if( mask & MTF_ALPHA) {
	*f++ = ALPHA;
	*f++ = mat->alpha;
    }

    *f = LMNULL;

    lmdef (DEFMATERIAL, astk->mat_seq, f - surface, surface);
}

void
mggl_setshader(mgshadefunc shader)
{
    register struct mgastk *ma = _mgc->astk;
    int wasusing = ma->useshader;

    ma->shader = shader;
    ma->useshader = (shader != NULL && IS_SHADED(ma->ap.shading));
    if(ma->useshader != wasusing)
	mggl_appearance(_mgc->astk, APF_SHADING);
}

void mggl_lighting(struct mgastk *astk, int mask)
{
  LtLight *light;
  LmLighting *li = &astk->lighting;

  if (li->valid) {
    mggl_lightmodeldef( astk->light_seq, li, li->valid & mask );
    lmbind(LMODEL, astk->light_seq);
  }

  mmode(MVIEWING);
  pushmatrix();
  loadmatrix( _mgc->W2C );
  mggl_lights( li->lights, astk );
  popmatrix();
}

void
mggl_lights( LtLight *light, struct mgastk *astk )
{
  int i, lightsused;
  int baselight = -1;

  /* unbind all currently bound GL lights */
  for (i=0; i<MAXLIGHTS; ++i) {
    lmbind(LIGHT0+i, 0);
  }

  lightsused = 0;
  while (light) {
    if (light->Private == 0) {
      /* this is a new light */
      if(baselight < 0) {
	register struct mgastk *a;
	for(a = astk, baselight = 1; a != NULL; a = a->next)
	    baselight += MAXLIGHTS; /* Count appearance stack depth */
      }
      light->Private = lightsused + baselight;
      light->changed = 1;  /* set changed, to force lmdef below */
    }

    if( light->changed ) {
      mggl_lightdef( light->Private, light );
      light->changed = 0;
    }
    lmbind( LIGHT0+lightsused, light->Private );
    ++lightsused;
    light = light->next;
  }
}


int
mggl_lightdef( int lightno, LtLight *light)
{
    float lightsource[MAXDEF];
    float *f = lightsource;

    *f++ = AMBIENT;
    *f++ = light->ambient.r;
    *f++ = light->ambient.g;
    *f++ = light->ambient.b;

    *f++ = LCOLOR;
    *f++ = light->intensity * light->color.r;
    *f++ = light->intensity * light->color.g;
    *f++ = light->intensity * light->color.b;

    *f++ = POSITION;
    *f++ = light->globalposition.x;
    *f++ = light->globalposition.y;
    *f++ = light->globalposition.z;
    *f++ = light->globalposition.w;

    *f++ = LMNULL;
    lmdef( DEFLIGHT, lightno, f-lightsource, lightsource );
    return lightno;
}


int
mggl_lightmodeldef(int lightmodel, LmLighting *lgt, int mask)
{
    float light[40];
    float *f = light;

    if( mask & LMF_AMBIENT) {
	*f++ = AMBIENT;
	*f++ = lgt->ambient.r;
	*f++ = lgt->ambient.g;
	*f++ = lgt->ambient.b;
    }

    if( mask & LMF_LOCALVIEWER) {
	*f++ = LOCALVIEWER;
	*f++ = lgt->localviewer;
    }

    if( mask & (LMF_ATTENC | LMF_ATTENM)) {
	*f++ = ATTENUATION;
	*f++ = lgt->attenconst;
	*f++ = lgt->attenmult;
    }
#ifdef don_t_do_this
	/* This causes trouble if the vertex order makes GL consider
	 * our polygon to be backfacing -- then TWOSIDE causes it
	 * to be mis-shaded from both sides..
	 */
    if(_mgglc->cantwoside) {
	*f++ = TWOSIDE;		/* Always enable TWOSIDE lighting if hardware */
	*f++ = 1.0;		/* supports it.  (is this a good idea?) */
    }
#endif

    *f++ = LMNULL;
    lmdef (DEFLMODEL, lightmodel, f-light, light);
    return lightmodel;
}


/*-----------------------------------------------------------------------
 * Function:	mggl_d4f
 * Description:	wrapper for c4f
 * Args:	c:
 * Returns:	
 * Author:	munzner
 * Date:	Wed Sep 18 21:48:08 1991
 * Notes:	We must multiply by kd (diffuse coefficient of the material)
 * 		since we called lmcolor(LMC_DIFFUSE) earlier in mggl_material
 * 		so we're overwriting the diffuse material with every
 *		c4f call.
 */
void
mggl_d4f(c)
    float c[4];
{
    float d[4];
    d[0] = c[0] * kd;
    d[1] = c[1] * kd;
    d[2] = c[2] * kd;
    d[3] = c[3];
    /* Let appearance alpha override object's alpha */
    if (_mgc->astk->mat.valid & MTF_ALPHA &&
	_mgc->astk->mat.override & MTF_ALPHA)
      d[3] = _mgc->astk->mat.alpha;
    c4f(d);
}


void
mggl_n3fevert(register Point3 *n, register HPoint3 *p)
{
    Point3 tn;
    register Point3 *cp;

    if(!(_mgc->has & HAS_CPOS))
	mg_findcam();
    cp = &_mgc->cpos;
    if( (p->x-cp->x) * n->x + (p->y-cp->y) * n->y + (p->z-cp->z) * n->z > 0) {
	tn.x = -n->x;
	tn.y = -n->y;
	tn.z = -n->z;
	n3f((float *)&tn);
    } else {
	n3f((float *)n);
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.