[BACK]Return to ASD_align.c CVS log [TXT][DIR] Up to [Development] / performer / src / pguide / libpf / C

File: [Development] / performer / src / pguide / libpf / C / ASD_align.c (download)

Revision 1.1, Tue Nov 21 21:39:36 2000 UTC (16 years, 11 months ago) by flynnt
Branch: MAIN
CVS Tags: HEAD

Initial check-in based on OpenGL Performer 2.4 tree.
-flynnt

/*
 * Copyright 1995, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 *
 * This source code ("Source Code") was originally derived from a
 * code base owned by Silicon Graphics, Inc. ("SGI")
 * 
 * LICENSE: SGI grants the user ("Licensee") permission to reproduce,
 * distribute, and create derivative works from this Source Code,
 * provided that: (1) the user reproduces this entire notice within
 * both source and binary format redistributions and any accompanying
 * materials such as documentation in printed or electronic format;
 * (2) the Source Code is not to be used, or ported or modified for
 * use, except in conjunction with OpenGL Performer; and (3) the
 * names of Silicon Graphics, Inc.  and SGI may not be used in any
 * advertising or publicity relating to the Source Code without the
 * prior written permission of SGI.  No further license or permission
 * may be inferred or deemed or construed to exist with regard to the
 * Source Code or the code base of which it forms a part. All rights
 * not expressly granted are reserved.
 * 
 * This Source Code is provided to Licensee AS IS, without any
 * warranty of any kind, either express, implied, or statutory,
 * including, but not limited to, any warranty that the Source Code
 * will conform to specifications, any implied warranties of
 * merchantability, fitness for a particular purpose, and freedom
 * from infringement, and any warranty that the documentation will
 * conform to the program, or any warranty that the Source Code will
 * be error free.
 * 
 * IN NO EVENT WILL SGI BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT
 * LIMITED TO DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES,
 * ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED WITH THE
 * SOURCE CODE, WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT OR
 * OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM,
 * OR AROSE OUT OF USE OR RESULTS FROM USE OF, OR LACK OF ABILITY TO
 * USE, THE SOURCE CODE.
 * 
 * Contact information:  Silicon Graphics, Inc., 
 * 1600 Amphitheatre Pkwy, Mountain View, CA  94043, 
 * or:  http://www.sgi.com
 *
 * 
 *	ASD_align [asd_filename model_filename]
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <Performer/pf.h>
#include <Performer/pfdu.h>

#define EYE_RADIUS	100.0
#define RADIUS		40.0

#define	NOF_OBJECTS		100

static void 		init_globals(void);
static pfNode		*setup_ASD_align(pfNode *model, pfASD *asd, float *v);
static pfMaterial 	*defaultMaterial (void);
static pfGeoState 	*make_gstate (void);
static void 		advance_motion(void);

float		model_azimuth;

char		asd_filename[300];
char		model_filename[300];
char		texture_filename[300];

pfASD		*asd;
pfNode	 	*model;
float		cx, cy;
float		dx, dy;
pfBox		asd_box;
pfBox		model_box;
int		query_id;
pfFlux		*azimuth_flux;


/*===========================================================================*/
void main (int argc, char *argv[])
/*===========================================================================*/
{
    float       	t = 0.0f;
    pfScene     	*scene;
    pfPipe      	*p;
    pfChannel   	*chan;
    pfPipeWindow	*pwin;
    float		base_position[3];
    pfLight     	*lt;
    pfGeoState 		*gs, **gsa;


    init_globals();

    if (argc == 3)
    {
	strcpy (asd_filename, argv[1]);
	strcpy (model_filename, argv[2]);
    }

    /* Initialize Performer */
    pfInit();	

    pfuInit();

    /* 
     * Use different mode for spawning DBase thread.
     */
    pfMultiprocess(PFMP_APPCULLDRAW | PFMP_FORK_COMPUTE);			

    /* 
     * Configure multiprocessing mode and start parallel
     * processes. 
     */
    pfdInitConverter(asd_filename);
    pfdInitConverter(model_filename);
    pfConfig();			

    scene = pfNewScene();

    /* Load ASD. */
    pfFilePath(".:/usr/share/Performer/data:/usr/share/Performer/data/asddata");
    asd = (pfASD *) pfdLoadFile (asd_filename);
    if (! asd)
    {
	fprintf (stderr, "ASD file %s not loaded.\n", asd_filename);
	pfExit();
	exit(8);
    }

    pfASDSyncGroup(asd,1);
    pfAddChild(scene, asd);

    /* calculate center of model circular motion. */
    pfGetASDBBox (asd, &asd_box);
    cx = (asd_box . min[0] + asd_box . max[0]) * 0.5;
    cy = (asd_box . min[1] + asd_box . max[1]) * 0.5;

    dx = (asd_box . max[0] - asd_box . min[0]) * 0.5;
    dy = (asd_box . max[1] - asd_box . min[1]) * 0.5;

    /* setup gstate with some texture */
    gsa = pfMalloc(sizeof(pfGeoState*), pfGetSharedArena());
    gs = make_gstate();
    *gsa = gs;
    pfASDGStates(asd, gsa, 1);
    pfFree(gsa);


    /* Load model.  */
    model = pfdLoadFile (model_filename);
    if (! model)
    {
	fprintf (stderr, "Model file %s not loaded.\n", model_filename);
	pfExit();
	exit(8);
    }

    /*
     *	============================================================
     * 	Setup alignment
     *	============================================================
     */
    base_position[0] = cx;
    base_position[1] = cy;
    base_position[2] = 0;

    pfAddChild(scene, setup_ASD_align(model, asd, base_position));



    /* Configure and open GL window */
    p = pfGetPipe(0);

    pwin = pfNewPWin (p);
    pfPWinType (pwin, PFWIN_TYPE_X);
    pfPWinOriginSize (pwin, 0, 0, 500, 500);
    pfOpenPWin (pwin);

    /* Create and configure a pfChannel. */
    chan = pfNewChan(p);	
    pfChanScene(chan, scene);
    pfChanNearFar(chan, 1.0f, 100000.0f);
    pfChanFOV(chan, 45.0f, 0.0f);

    pfInitClock (0.0f);

    /* Make some light */

    pfEnable(PFEN_LIGHTING);
    lt = pfNewLight(pfGetSharedArena());
    pfLightPos(lt, 0.0f, 0.0f, 1.0f, 0.0f);
    pfLightOn(lt);

    pfEnable(PFEN_TEXTURE);

    /* Simulate for twenty seconds. */
    while (t < 200.0f)
    {
	pfCoord	   	view;
	float		x, y, z, pitch, cz;

	advance_motion();

	/* Go to sleep until next frame time. */
	pfSync();		

	/* Initiate cull/draw for this frame. */
	pfFrame();		

	/* Compute new view position. */
	t = pfGetTime();

	cz = (model_box . min[2] + model_box . max[2]) * 0.5;

	x = cx + EYE_RADIUS;
	y = cy - EYE_RADIUS;
	z = cz + EYE_RADIUS;

	pitch = - atan2 (fabs(z - cz), sqrt ((x-cx)*(x-cx) + (y-cy)*(y-cy))) 
			* 180.0 / M_PI;

        pfSetVec3(view.hpr, 45.0f, pitch, 0);
        pfSetVec3(view.xyz, x, y, z);

	pfChanView(chan, view.xyz, view.hpr);
    }

    /* Terminate parallel processes and exit. */
    pfExit();
}


/*===========================================================================*/
static void advance_motion(void)
/*===========================================================================*/
{
    float	v[3], d[3];
    float	*azimuth;

    model_azimuth += 0.01;
    if (model_azimuth > 2.0 * M_PI)
	model_azimuth -= 2.0 * M_PI;

    v[0] = cx + RADIUS * cos (model_azimuth);
    v[1] = cy + RADIUS * sin (model_azimuth);
    v[2] = 0.0;

    d[0] = 0.0;
    d[1] = 0.0;
    d[2] = -1.0;

    pfASDQueryArrayElement (asd, query_id, 0, v, d);

    azimuth = (float *) pfGetFluxWritableData (azimuth_flux);

    azimuth[0] = cos (model_azimuth + M_PI * 0.5);
    azimuth[1] = sin (model_azimuth + M_PI * 0.5);

    pfFluxWriteComplete (azimuth_flux);

}


/*===========================================================================*/
static void init_globals(void)
/*===========================================================================*/
{
    strcpy (asd_filename, "tinyASD.pfb");
    strcpy (model_filename, "esprit.flt");
    strcpy (texture_filename, "marble.rgb");
    model_azimuth = 0.0;
}


/*===========================================================================*/
static pfNode	*setup_ASD_align(pfNode *model, pfASD *asd, float *v)
/*===========================================================================*/
{
    /*
     *  =====================
     *  Final tree structure:
     *  =====================
     *
     *      <pfLOD>                                 <asd>
     *         |                                      |
     *       <FCS> <----[matrix_flux]<--[engine]<--[query_flux]    in pfCompute 
     *         |                           |
     *      <pfNode>                       <-------[azimuth_flux]  in APP
     *      /      \
     *        Model 
     */

    /*
     *	Note: Multiple writers into matrix_flux. Both the pfCompute process 
     *  and the APP process cause engine source changes. We make azimuth_flux
     *	a NO-PUSH flux and query_flux a PUSH flux in order to avoid conflicts.
     */

    pfFlux	*matrix_flux, *query_flux;
    pfFCS	*fcs;
    pfEngine	*engine;
    pfLOD	*lod;
    pfSphere	sphere;
    pfSphere    big_sphere;
    pfBox       *box_p;
    float	*s_position, *s_down;
    pfMatrix	M;
    float	azimuth[3];

    /*
     *  ==================================================================
     *  Copy position to shared memory.
     *  ==================================================================
     */
    s_position = (float *) pfMalloc(3 * sizeof(float), pfGetSharedArena());

    s_position[0] = v[0];
    s_position[1] = v[1];
    s_position[2] = v[2];

    s_down = (float *) pfMalloc(3 * sizeof(float), pfGetSharedArena());

    s_down[0] = 0.0;
    s_down[1] = 0.0;
    s_down[2] = -1.0;

    /*
     *  ==================================================================
     *  Make a FCS. Put the object under it.
     *  ==================================================================
     */

    matrix_flux = pfNewFlux(sizeof(pfMatrix),
                            4 + PFFLUX_DEFAULT_NUM_BUFFERS, pfGetSharedArena());
    pfFluxSyncGroup(matrix_flux, 1);

    pfMakeTransMat (M, v[0], v[1], v[2]);
    pfFluxInitData (matrix_flux, M);

    fcs = pfNewFCS(matrix_flux);

    pfAddChild(fcs, model);

    pfGetNodeBSphere(fcs, &sphere);

    /*
     *  =====================================================================
     *  Make flux for APP control over azimuth.
     *
     *  The azimuth Flux is NOT in push mode. When the ASD Compute task is 
     *	very busy, and azimuth_flux is in push mode, we miss some of the 
     * 	pfASD updates. in Push mode, the azimuth_flux competes with pfASD on 
     *	writing to matrix_flux and it sometimes overwrites the ASD results. 
     *  =====================================================================
     */

    azimuth_flux = pfNewFlux(3 * sizeof(float),
                            4 + PFFLUX_DEFAULT_NUM_BUFFERS, pfGetSharedArena());
    azimuth[0] = 0.0;
    azimuth[1] = 1.0;
    azimuth[2] = 0.0;

    pfFluxInitData(azimuth_flux, azimuth);
    pfFluxMode(azimuth_flux, PFFLUX_PUSH, PF_OFF);

    /*
     *  =====================================================================
     *  Align object to terrain 
     *  =====================================================================
     */
    query_flux = pfNewFlux(2 * 3 * sizeof(float),
                            4 + PFFLUX_DEFAULT_NUM_BUFFERS, pfGetSharedArena());
    pfFluxMode(query_flux, PFFLUX_PUSH, PF_ON);

    query_id = pfASDAddQueryArray(asd, s_position, s_down, 1,
                                  PR_QUERY_POSITION | PR_QUERY_NORMAL,
                                  query_flux);

    engine = pfNewEngine(PFENG_ALIGN, pfGetSharedArena());
    pfEngineSrc(engine, PFENG_ALIGN_POSITION, query_flux, NULL, 0, 0, 0);
    pfEngineSrc(engine, PFENG_ALIGN_NORMAL, query_flux, NULL, 0, 3, 0);
    pfEngineSrc(engine, PFENG_ALIGN_AZIMUTH, azimuth_flux, NULL, 0, 0, 0);

    pfEngineDst(engine, matrix_flux, NULL, 0, 0);
    /*
     *  Evaluation Range
     */
    pfEngineEvaluationRange(engine, sphere.center, 0.0, 100000.0);
    pfEngineMode(engine, PFENG_RANGE_CHECK, PF_ON);

    pfASDGetQueryArrayPositionSpan(asd, query_id, &model_box);

    /*
     *  ==================================================================
     *  Calculate the maximum bbox of the morphing object.
     *  ==================================================================
     */
    box_p = & model_box;
    pfSphereAroundBoxes(&big_sphere, (const pfBox **)&box_p, 1);

    lod = pfNewLOD();
    pfAddChild(lod, fcs);

    pfLODRange(lod, 0, 0.0);
    pfLODRange(lod, 1, 100000.0 + big_sphere.radius);
    pfLODCenter(lod, big_sphere.center);

    pfNodeBSphere(lod, &big_sphere, PFBOUND_STATIC);
    pfNodeBSphere(fcs, &big_sphere, PFBOUND_STATIC);

    return((pfNode *)lod);
}

/*===========================================================================*/
static pfGeoState *make_gstate (void)
/*===========================================================================*/
{
    pfGeoState 	*gs;
    pfTexture  	*tex;
    pfTexGen	*tgen;
    float	s;

    s = 1.0 / (asd_box . max[0] - asd_box . min[0]);

    gs = pfNewGState (pfGetSharedArena());
    tex = pfNewTex( pfGetSharedArena());
    tgen = pfNewTGen( pfGetSharedArena());

    pfMakeBasicGState(gs);
    pfGStateMode(gs, PFSTATE_CULLFACE, PFCF_BACK);
    pfGStateMode(gs, PFSTATE_ENLIGHTING, PF_ON);
    pfGStateMode(gs, PFSTATE_ENTEXTURE, PF_ON);
    pfGStateAttr(gs, PFSTATE_FRONTMTL, defaultMaterial());

    pfLoadTexFile( tex, texture_filename );
    pfGStateAttr( gs, PFSTATE_TEXTURE, tex );

    pfGStateMode(gs, PFSTATE_ENTEXGEN, PF_ON);

    pfGStateAttr( gs, PFSTATE_TEXGEN, tgen );
    pfGStateAttr( gs, PFSTATE_TEXENV, pfNewTEnv( pfGetSharedArena() ) );

    pfTGenPlane(tgen, PF_S,   s, 0.0, 0.0, 0.0);
    pfTGenPlane(tgen, PF_T, 0.0,   s, 0.0, 0.0);
    pfTGenPlane(tgen, PF_R, 0.0, 0.0,   s, 0.0);
    pfTGenPlane(tgen, PF_Q, 0.0, 0.0, 0.0, 1.0);

    pfTGenMode(tgen, PF_S, PFTG_OBJECT_LINEAR);
    pfTGenMode(tgen, PF_T, PFTG_OBJECT_LINEAR);
    pfTGenMode(tgen, PF_R, PFTG_OBJECT_LINEAR);
    pfTGenMode(tgen, PF_Q, PFTG_OBJECT_LINEAR);

    return (gs);
}

/*===========================================================================*/
static pfMaterial *defaultMaterial (void)
/*===========================================================================*/
{
    pfMaterial	*material;

    material = pfNewMtl(pfGetSharedArena());
    pfMtlColor(material, PFMTL_AMBIENT,  0.8f, 0.8f, 0.8f);
    pfMtlColor(material, PFMTL_DIFFUSE,  0.8f, 0.8f, 0.8f);
    pfMtlColor(material, PFMTL_SPECULAR, 0.0f, 0.0f, 0.0f);
    pfMtlShininess(material, 0.0f);

    pfMtlColorMode(material, PFMTL_FRONT, PFMTL_CMODE_OFF);
    return material;
}