/*
* 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_decal [-A][asd_filename]
*
* $Revision: 1.1 $ $Date: 2000/11/21 21:39:36 $
*
* Demonstrate how to generate decals pfASD.
*
* The program generates a flux to receive query results from pfASD.
* This flux is a source of a user defined pfEngine. The engine copies
* the resulting geometry into a fluxed pfGeoSet. This pfGeoset is
* on the scene graph (so we see it).
*
* This is a somewhat complex setup but it allows for APP intervention in
* the copy from the pfASD result to the final pfGeoSet (e.g. When the
* decal is a shadow, ignore some of the resulting triangles that fall
* far away from the object casting the shadow. Alpha blend to get a
* smooth vanishing effect).
*
* Without flags: generate an animated triangular decal (move in a circle).
* -A : disable motion
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <Performer/pf.h>
#include <Performer/pfdu.h>
#define EYE_RADIUS 400.0
#define SIZE 100.0
#define NOF_FRAGMENTS 200
static void init_globals(void);
static pfMaterial *defaultMaterial (void);
static pfGeoState *make_asd_gstate (void);
static void advance_motion(void);
static pfNode *setup_ASD_decal(pfASD *asd, pfGeoSet *base_gset);
static int fluxed_gset_create_func (pfFluxMemory *fmem);
static void decal_engine (pfEngine *_engine);
static pfFlux *make_fluxed_geoset(void);
static pfGeoSet *make_base_gset (void);
float decal_azimuth;
char asd_filename[300];
char texture_filename[300];
pfASD *asd;
float cx, cy;
float dx, dy;
pfBox asd_box;
pfBox decal_box;
int query_id;
pfGeoSet *decal_gset;
pfGeoSet *base_gset;
float *global_v_attr;
int animate_decal;
/*===========================================================================*/
int main (int argc, char *argv[])
/*===========================================================================*/
{
float t = 0.0f;
pfScene *scene;
pfPipe *p;
pfChannel *chan;
pfPipeWindow *pwin;
int i;
pfLight *lt;
pfGeoState *gs, **gsa;
pfNode *node;
init_globals();
for (i = 1 ; i < argc ; i ++)
{
if (argv[i][0] == '-')
{
if (argv[i][1] == 'A')
animate_decal = 0;
}
else
strcpy (asd_filename, argv[1]);
}
/* 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);
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_asd_gstate();
*gsa = gs;
pfASDGStates(asd, gsa, 1);
pfFree(gsa);
/*
* ============================================================
* Setup alignment
* ============================================================
*/
base_gset = make_base_gset();
node = setup_ASD_decal(asd, base_gset);
pfAddChild(scene, node);
/*
* ============================================================
* other common setup.
* ============================================================
*/
/* 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;
if (animate_decal)
advance_motion();
/* Go to sleep until next frame time. */
pfSync();
/* Initiate cull/draw for this frame. */
pfFrame();
/* Compute new view position. */
t = pfGetTime();
cz = (decal_box . min[2] + decal_box . max[2]) * 0.5;
x = cx + EYE_RADIUS;
y = cy - EYE_RADIUS;
z = cz + 1.5 * 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();
exit(0);
}
/*===========================================================================*/
static void advance_motion(void)
/*===========================================================================*/
{
float *v;
ushort *dummy_ushort;
float down[3];
pfGetGSetAttrLists(base_gset, PFGS_COORD3, (void **) &v, &dummy_ushort);
decal_azimuth += 0.01;
if (decal_azimuth > 2.0 * M_PI)
decal_azimuth -= 2.0 * M_PI;
v[0] = cx;
v[1] = cy;
v[2] = 0.0;
v[3] = cx + SIZE * cos(decal_azimuth);
v[4] = cy + SIZE * sin(decal_azimuth);
v[5] = 0.0;
v[6] = cx + SIZE * cos(decal_azimuth + M_PI * 0.25);
v[7] = cy + SIZE * sin(decal_azimuth + M_PI * 0.25);
v[8] = 0.0;
pfGSetAttr(base_gset, PFGS_COORD3, PFGS_PER_VERTEX, v, NULL);
down[0] = 0.0;
down[1] = 0.0;
down[2] = -1.0;
pfASDReplaceQueryGeoSet (asd, query_id, base_gset, down);
}
/*===========================================================================*/
static void init_globals(void)
/*===========================================================================*/
{
strcpy (asd_filename, "tinyASD.pfb");
strcpy (texture_filename, "marble.rgb");
decal_azimuth = 0.0;
animate_decal = 1;
}
/*===========================================================================*/
static pfNode *setup_ASD_decal(pfASD *asd, pfGeoSet *base_gset)
/*===========================================================================*/
{
/*
* =====================
* Final tree structure:
* =====================
*
* <pfLOD> <asd> <-- base_gset
* | |
* <Geode> |
* | V
* [Fluxed pfGeoSet]-----[user engine]---[query_flux]
*
*/
pfFlux *query_flux;
pfEngine *engine;
pfLOD *lod;
pfGeoSet *gset;
pfFlux *fluxed_gset;
pfGeode *geode;
pfSphere sphere;
pfSphere big_sphere;
pfBox *box_p;
float *s_down;
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 fluxed geoset. Add to a geode.
* =====================================================================
*/
fluxed_gset = make_fluxed_geoset();
gset = (pfGeoSet*) pfGetFluxCurData (fluxed_gset);
pfFluxSyncGroup((pfFlux *) fluxed_gset, 1);
geode = pfNewGeode();
pfAddGSet (geode, gset);
/*
* =====================================================================
* Add a pfASD query for the input base_gset
* Allow generation of NOF_FRAGMENTS decal fragments for a query result.
* =====================================================================
*/
query_flux = pfNewFlux((1 + NOF_FRAGMENTS * 3 * 3 ) * sizeof(float),
4 + PFFLUX_DEFAULT_NUM_BUFFERS, pfGetSharedArena()); pfFluxMode(query_flux, PFFLUX_PUSH, PF_ON);
query_id = pfASDAddQueryGeoSet (
asd,
base_gset,
s_down,
PR_QUERY_TRI_COORD,
query_flux);
pfASDGetQueryArrayPositionSpan(asd, query_id, &decal_box);
/*
* =====================================================================
* Make a user_func engine.
* =====================================================================
*/
engine = pfNewEngine (PFENG_USER_FUNCTION, pfGetSharedArena());
pfEngineUserFunction (engine, decal_engine);
pfEngineSrc (engine, 0, query_flux, 0, 0, 0, 0);
pfEngineDst (engine, fluxed_gset, 0, 0, 0);
sphere . center[0] = cx;
sphere . center[1] = cy;
sphere . center[2] = (decal_box . min[2] + decal_box . max[2]) * 0.5;
sphere . radius = SIZE;
/*
* Evaluation Range
*/
pfEngineEvaluationRange(engine, sphere.center, 0.0, 100000.0);
pfEngineMode(engine, PFENG_RANGE_CHECK, PF_ON);
/*
* ==================================================================
* Calculate the maximum bbox of the morphing object.
* ==================================================================
*/
box_p = & decal_box;
pfSphereAroundBoxes(&big_sphere, (const pfBox **)&box_p, 1);
lod = pfNewLOD();
pfAddChild(lod, geode);
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(geode, &big_sphere, PFBOUND_STATIC);
return((pfNode *)lod);
}
/*===========================================================================*/
static pfGeoState *make_asd_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;
}
/*===========================================================================*/
static int fluxed_gset_create_func (pfFluxMemory *fmem)
/*===========================================================================*/
{
float *v_attr, *c_attr;
pfGeoState *gstate;
pfGeoSet *gset;
if (fmem == NULL)
return pfFluxedGSetInit(fmem);
pfFluxedGSetInit(fmem);
gset = (pfGeoSet*)pfGetData(fmem);
v_attr = (float *) pfCalloc(sizeof (float) * 3 * 3 * NOF_FRAGMENTS, 1,
pfGetSharedArena());
c_attr = pfMalloc(4 * sizeof(float), pfGetSharedArena());
c_attr[0] = 0.1;
c_attr[1] = 0.1;
c_attr[2] = 0.1;
c_attr[3] = 0.6;
pfGSetAttr(gset, PFGS_COLOR4, PFGS_OVERALL, c_attr, NULL);
/*
* ===========================================================
* Build state.
* ===========================================================
*/
gstate = pfNewGState (pfGetSharedArena());
pfMakeBasicGState (gstate);
pfGStateMode (gstate, PFSTATE_CULLFACE, PFCF_OFF);
pfGStateMode (gstate, PFSTATE_ENLIGHTING, PF_OFF);
pfGStateMode (gstate, PFSTATE_TRANSPARENCY, PFTR_ON | PFTR_NO_OCCLUDE);
pfGStateMode(gstate, PFSTATE_DECAL,
PFDECAL_LAYER_DISPLACE | PFDECAL_LAYER_7 | PFDECAL_LAYER_OFFSET);
pfGStateMode (gstate, PFSTATE_ENTEXTURE, 0);
/*
* ===========================================================
* Gset attributes.
* ===========================================================
*/
pfGSetPrimType(gset, PFGS_TRIS);
pfGSetNumPrims(gset, 0);
pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, v_attr, NULL);
pfGSetGState(gset, gstate);
return 0;
}
/*===========================================================================*/
static pfFlux *make_fluxed_geoset(void)
/*===========================================================================*/
{
pfFlux *fluxed_gset;
fluxed_gset = pfNewFluxInitFunc (
fluxed_gset_create_func,
PFFLUX_DEFAULT_NUM_BUFFERS,
pfGetSharedArena());
return fluxed_gset;
}
/*============================================================================*/
static void decal_engine (pfEngine *_engine)
/*============================================================================*/
{
void *dst, *src;
int d_offset, s_offset;
ushort *d_ilist, *s_ilist;
int d_stride, s_stride;
int s_icount;
float *f_asd_data;
int *i_asd_data;
pfGeoSet *gset;
int i;
float *v_ptr, *o_ptr;
int nof_triangles;
ushort *foo;
pfGetEngineDst (_engine, &dst, &d_ilist, &d_offset, &d_stride);
pfGetEngineSrc
(_engine, 0, &src, &s_ilist, &s_icount, &s_offset, &s_stride);
if (pfGetEngineNumSrcs(_engine) != 1 || dst == NULL || src == NULL)
{
fprintf(stderr, "decal_engine (0x%08x) Bad config.\n", (void*)_engine);
return;
}
/*
* ==============================================================
* Grab pointers to most current src/dst Flux buffers.
* ==============================================================
*/
f_asd_data = pfGetFluxCurData ((pfFlux *) src);
i_asd_data = (int *) f_asd_data;
nof_triangles = i_asd_data [0];
gset = pfGetFluxWritableData ((pfFlux *) dst);
pfGetGSetAttrLists (gset, PFGS_COORD3, (void **) &v_ptr, &foo);
o_ptr = & f_asd_data[1];
for (i = 0 ; i < nof_triangles ; i ++)
{
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
*(v_ptr ++) = *(o_ptr ++);
}
pfGSetNumPrims(gset, nof_triangles);
}
/*===========================================================================*/
static pfGeoSet *make_base_gset (void)
/*===========================================================================*/
{
pfGeoSet *gset;
float *v;
gset = pfNewGSet (pfGetSharedArena());
pfGSetPrimType(gset, PFGS_TRIS);
pfGSetNumPrims(gset, 1);
v = pfMalloc (9 * sizeof (float), pfGetSharedArena());
v[0] = cx;
v[1] = cy;
v[2] = 0.0;
v[3] = cx + SIZE;
v[4] = cy;
v[5] = 0.0;
v[6] = cx;
v[7] = cy + SIZE;
v[8] = 0.0;
pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, v, NULL);
return (gset);
}