ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/lib/gprim/discgrp/dgdraw.c

This is dgdraw.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. */

/* july 25, 1993: I tried to make an improvement in order to make a 
 * better video for my siggraph talk here but decided against it.
 */
/* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */

#include "discgrpP.h"
#include "mgP.h"
#include "math.h"


DiscGrp *
DiscGrpDraw(register DiscGrp *discgrp)
{
	static HPoint3 origin = {0,0,0,1}, cpos;
	static Transform c2m;   /* it's used in the DiscGrp data struc */
	Transform w2c, c2w, cinv, m2w, w2m,
		m2c, h, hprime, c2wprime;
	Transform invtlate, tmp, tlate;
	DiscGrpEl *nhbr;
	int i, metric;
	float fov, cfov;
	float halfy, aspect, halfx;
	static float magic_scale = 1.4;

    metric = discgrp->attributes & DG_METRIC_BITS;
    /*  make sure we have some geometry to display; the control code
     *	is a bit suspiciously topheavy  */
    if (discgrp->geom == NULL || discgrp->flag & DG_NEWDIRDOM ||
	(discgrp->flag & DG_DRAWDIRDOM && discgrp->ddgeom == NULL)) {
      	Appearance *ap;
      	float scale;
      	discgrp->ddgeom = DiscGrpDirDom(discgrp);
	if (discgrp->geom == NULL ) discgrp->geom = discgrp->ddgeom;
        /* turn off the alarm */
	discgrp->flag &= ~DG_NEWDIRDOM;
	if (!discgrp->ddgeom)	{
	    OOGLError(1,"DiscGrpDraw: Unable to create dirichlet domain\n");
	    }
        }

    /* be sure we have some group elements */
    if (discgrp->big_list == NULL )
      if (discgrp->nhbr_list != NULL) 
	discgrp->big_list = discgrp->nhbr_list;
      else 	return(discgrp);

    /* we're about to mess around with the camera matrix; before doing so,
    get the current one (it's already been set for this frame) to use in
    culling later on */
    if (discgrp->flag  & DG_ZCULL)	{
        /* get the pieces of the model to viewing transform */
	CamGet(_mgc->cam, CAM_W2C, w2c);
        /* concatenate the model to world coordinate transform */
        mg_gettransform(m2w);
        TmConcat(m2w, w2c, m2c);
	CamGet(_mgc->cam, CAM_FOV, &fov);
	CamGet(_mgc->cam, CAM_HALFYFIELD, &halfy);
	CamGet(_mgc->cam, CAM_ASPECT, &aspect);
	halfy = halfy * magic_scale;
	halfx = aspect * halfy;

	/* Hack to get culling to work -Celeste */
	halfx = (halfx > halfy) ? halfx : halfy;
	halfy = halfx;

	/* use half + a fudge factor to compute cos of angle */
	/* currently this is badly broken so we have to use much bigger
	factor than we should have to */
 	fov = magic_scale * (3.14159/180.0) * fov;
	cfov = cos( (double) fov);
	}

    /* 
     * the main idea here is to find out the position of the current camera
     * and use it to make sure the group elements used are centered at the 
     * camera.  We do this by looking at the orbit of the origin and seeing
     * if the camera is closer to 
     */
    if (discgrp->flag & DG_CENTERCAM )	{
	/* get the camera transformation */
	CamGet(_mgc->cam, CAM_C2W, c2w);

	/* concatenate the model to world coordinate transform */
	mg_gettransform(m2w);
	TmInvert(m2w, w2m);
  	TmConcat(c2w, w2m, c2m);
	discgrp->c2m = (float (*)[4]) c2m;

	/* use it to derive the model coordinates of the camera */
	HPt3Transform(c2m, &origin, &cpos);	

	/* compute the group element which is 'closest' to the camera */
	nhbr = DiscGrpClosestGroupEl(discgrp, &cpos);	

	/* apply the inverse of this transform to the camera */
  	TmInvert(nhbr->tform, h);
	/* this requires conjugating cinv by the w2m transform: 
	 *
         *  C  --- c2w --->   W   ---- w2m ---->   M
	 *   \                |                    |
	 *    \  	      h'                 h = nhbr->tform inverse
	 *     c2w'	      |                    |
	 *	\--------->   W   <--- m2w -----   M
	 *
	 * In the above diagram we want c2w' = c2w h'
  	 */
	TmConcat(h, m2w, cinv);
	TmConcat(w2m, cinv, hprime);
	TmConcat(c2w, hprime, c2wprime);
	if (discgrp->attributes & DG_HYPERBOLIC && needstuneup(c2wprime)) {
	    tuneup(c2wprime, metric);
	    if (needstuneup(c2wprime))
	        OOGLError(1,"DiscGrpDraw: tuneup failed\n");
	    }
	CamSet(_mgc->cam, CAM_C2W, c2wprime, CAM_END);
	}

    {
    int viscnt = 0; 
    float ratio = 1.0;
    HPoint3 image, image2;
    int vis;
    float dx, dy, d;
    Transform tile2c;
    extern Geom *large_dd, *small_dd;	/*very ugly but appearances
		don't work correctly when pushed down into a list */
    Transform Tnew, T2;
    GeomIter *it;

    it = GeomIterate( (Geom *)discgrp, DEEP );
    /* loop through them */
    while(NextTransform(it, Tnew) > 0) {
	vis = 1;
	if (discgrp->flag  & DG_ZCULL)	{
            TmConcat(Tnew, m2c, tile2c);
            HPt3Transform(tile2c, &discgrp->cpoint, &image);
	    d = HPt3SpaceDistance(&image, &discgrp->cpoint, metric);
	    if (d > 2.0 )	{	/* only discard far-away tiles */
	      /* first discard the ones behind the eye, if that makes sense */
	      if (metric != DG_SPHERICAL && image.z*image.w > 0.0) vis = 0;
	      else {	/* then test outside the camera frustrum */
/*
	        HPt3Dehomogenize(&image, &image2);
		d = sqrt((double)(image2.z*image2.z + image2.x*image2.x));
*/
                if (fabs(image.x) > fabs(image.z * halfx) ) vis = 0;
	        else 	{
/*
	            HPt3R30Normalize(&image2);
		    d = sqrt((double)(image2.z*image2.z + image2.y*image2.y));
*/
                    if (fabs(image.y) > fabs(image.z * halfy) ) vis = 0;
	            }
		}
	      }
	      /* prevent jerky transitions of # of grp els */
	      if (d > discgrp->enumdist) vis = 0;
	    }

	if (vis)	{
	  viscnt++;
          mgpushtransform();
    	  mgtransform( Tnew );

	  /* while the appearance stuff doesn't work correctly, we have to
	   * commit some pretty terrible crimes...we'd like to be able to
	   * just say GeomDraw(discgrp->geom)...but we can't as long as
	   * appearances don't work as advertised */

    	  if (discgrp->ddgeom && discgrp->flag & DG_DRAWDIRDOM)    {
	   if (discgrp->flag & DG_DDBEAM)	GeomDraw(discgrp->ddgeom);
	   else {
            mgpushappearance();
            mgctxset(MG_ApSet, AP_DONT, APF_FACEDRAW, AP_DO, APF_EDGEDRAW, AP_END, MG_END);
            GeomDraw(large_dd);
            mgpopappearance();

    	    mgpushappearance();
            mgctxset(MG_ApSet, AP_DO, APF_FACEDRAW, AP_END, MG_END);
            GeomDraw(small_dd);
            mgpopappearance();
            }
	   }
          if (discgrp->flag & DG_DRAWGEOM && discgrp->geom && discgrp->geom != discgrp->ddgeom) 
		GeomDraw( discgrp->geom );

	  if ((discgrp->flag & DG_DRAWCAM) && (discgrp->camgeom)) {
	    mgpushtransform();
	    mgtransform( c2m );
	    GeomDraw(discgrp->camgeom);
	    mgpoptransform();
	    }

          mgpoptransform();
	  }
        }
    /* for debugging to see how culling works */
    ratio = viscnt / ((double) discgrp->big_list->num_el);
    }

    return(discgrp);
}

    		
#ifdef REASONABLE
 	TmScale( scaler, discgrp->scale, discgrp->scale, discgrp->scale);
	large = DiscGrpDirDom(discgrp, &discgrp->cpoint);
	large->ap = ApCreate(AP_DO, APF_EDGEDRAW, AP_DONT, APF_FACEDRAW, AP_END);
	ap = ApCreate(AP_DONT, APF_EDGEDRAW, AP_DO, APF_FACEDRAW, AP_END);
	small = GeomCreate("inst", CR_GEOM, large, CR_AXIS, scaler, CR_APPEAR, ap, CR_END);
	smlist = GeomCreate("list", CR_GEOM, small, CR_END);
	mylist = GeomCreate("list", CR_GEOM, large, CR_CDR, smlist, CR_END);
	discgrp->ddgeom = mylist;
 	TmScale( scaler, discgrp->scale, discgrp->scale, discgrp->scale);
	Tm3SpaceTranslateOrigin(tlate, &discgrp->cpoint, metric);
	/* perform translation so cpoint is at origin */
	TmInvert(tlate, invtlate);
	/* apply scaling transform centered at cpoint */
	TmConcat(invtlate, scaler, tmp);
	/* and move cpoint back to where it started */
	TmConcat(tmp, tlate, tmp);

	    d = HPt3SpaceDistance( &discgrp->cpoint, &image, metric);
#else
#endif

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