Re: calculating shadows

New Message Reply Date view Thread view Subject view Author view

Slimane Merzouk (merzouk++at++cthulhu.engr.sgi.com)
Tue, 29 Sep 1998 13:21:21 -0700


Jose Luis Garcia Nava wrote:
>
> Hi pfAll:
>
> I am also having trouble with shadows and cannot find the shadows.c
> program. I think it is not included in my 2.1 Performer distribution.
> Can anyone e-mail a copy to examine it?
>

Hi,
here is the shadows.c file.
         
        Slimane Merzouk.

/*
 * Copyright 1995-1996-1997, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 *
 * UNPUBLISHED -- Rights reserved under the copyright laws of the United
 * States. Use of a copyright notice is precautionary only and does not
 * imply publication or disclosure.
 *
 * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to restrictions
 * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or

 * Supplement. Contractor/manufacturer is Silicon Graphics, Inc.,
 * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that (i) the above copyright notices and this
 * permission notice appear in all copies of the software and related
 * documentation, and (ii) the name of Silicon Graphics may not be
 * used in any advertising or publicity relating to the software
 * without the specific, prior written permission of Silicon Graphics.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
 * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
 * THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 *
 * shadows.c: Performer program to demonstrate use of pfLightSource shadowing
 * and projected texturing.
 * Based on simple.c
 *
 * $Revision: 1.17 $ $Date: 1997/11/01 00:45:32 $
 *
 */

static int Floor= 0;
static Ambient = 0;
static int SpotOne=0;
static int SpotTwo=0;
static int Whites=0;
static int Shadow=0;
static int SpotTexture = 1;
static int enable_shadows = 1; /* disable shadows in HW does not handle it */

#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <Performer/pf.h>
#include <Performer/pfdu.h>
#include <Performer/pfutil.h>

/*------------------------------------------------------------------*/

static int FBAttrs[] = {
    PFFB_RGBA,
    PFFB_DOUBLEBUFFER,
#ifdef IRISGL
    PFFB_SAMPLES, 0,
    PFFB_ALPHA_SIZE, 1,
    PFFB_DEPTH_SIZE, 16,
#else
    PFFB_DEPTH_SIZE, 1,
#endif
    None,
};

char ProgName[PF_MAXSTRING];

void
OpenPipeWin (pfPipeWindow *pw)
{
    pfLightModel *lm;

    pfOpenPWin(pw);

    lm = pfNewLModel(NULL);
    pfLModelLocal(lm, 1);
    pfApplyLModel(lm);

    pfCullFace(PFCF_BACK);
}

/* ARGSUSED */
void
DrawChannel (pfChannel *chan, void *data)
{
    pfVec4 clr;
    pfSetVec4(clr, .2f, .2f, .2f, 1.0f);
    pfClear(PFCL_COLOR|PFCL_DEPTH, clr);
    pfDraw();
}

/*
 * Usage() -- print usage advice and exit. This
 * procedure is executed in the application process.
 */
static void
Usage (void)
{
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, "Usage: shadows [-1 -2 -a -s -f -w -t] file.ext ...\n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, " -1 : enable projected texture 1 \n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, " -2 : enable projected texture 2 \n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, " -a : enable regular light\n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, " -s : enable shadow \n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, " -f : use the texture floor5.rgb on the floor\n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, " -w : use white spots lights \n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, " -t : use texture myspot.tex for the projected textures\n");
    pfNotify(PFNFY_NOTICE, PFNFY_USAGE, "Default: -1 -2 -a -s -f\n");

    exit(1);
}

static void
Default(void)
{
    SpotOne = SpotTwo = Shadow = Ambient = Floor = 1;
}

/*
* docmdline() -- use getopt to get command-line arguments,
* executed at the start of the application process.
*/

static int
docmdline(int argc, char *argv[])
{
    int opt;

    strcpy(ProgName, argv[0]);
     
    /* process command-line arguments */
    while ((opt = getopt(argc, argv, "12asfwt")) != -1)
    {
        switch (opt)
        {
        case '1':
            SpotOne = 1;
            break;
        case '2':
            SpotTwo = 1;
            break;
        case 's':
            Shadow = 1;
            break;
        case 'f':
            Floor = 1;
            break;
        case 't':
            SpotTexture = 1;
            break;
        case 'a':
            Ambient = 1;
            break;
        case 'w':
            Whites = 1;
            break;
        case 'h':
            Usage();
        }
    }
    return optind;
}

/* Compute matrix so +Y axis of DCS is pointing at 'at' */
static void
lookAt(pfDCS *dcs, pfVec3 at)
{
    pfVec3 v, pos;
    pfMatrix mat;
    static pfVec3 yaxis = {0.0f, 1.0f, 0.0f};
     
    /* v is origin of dcs */
    pfGetMatRowVec3(*pfGetDCSMatPtr(dcs), 3, pos);
     
    /* v is direction vector from dcs to 'at' */
    pfSubVec3(v, at, pos);
    pfNormalizeVec3(v);

    /* Rotate y-axis onto v */
    pfMakeVecRotVecMat(mat, yaxis, v);
    pfSetMatRowVec3(mat, 3, pos); /* restore dcs origin */
    pfDCSMat(dcs, mat);
}

#define SPOT_SIZE 256
#define SPOT_RADIUS 64

/*
 * Create circular image for projected spotlight texture.
*/
static pfTexture*
initSpotTex(void)
{
    long i, j;
    pfTexture *tex;
    unsigned short *image;

    image = pfMalloc(sizeof(unsigned short) * SPOT_SIZE * SPOT_SIZE,
                     pfGetSharedArena());

    for (i = 0; i < SPOT_SIZE / 2; i++)
    {
        for (j = 0; j < SPOT_SIZE / 2; j++)
        {
            unsigned long val;

            val = 0;

            /* See if corners of texel are within circle. This antialiases
             * the edge of the circle somewhat. */
            if ((i * i + j * j) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;
            if (((i + 1) * (i + 1) + j * j) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;
            if (((i + 1) * (i + 1) + (j + 1) * (j + 1)) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;
            if ((i * i + (j + 1) * (j + 1)) <= SPOT_RADIUS * SPOT_RADIUS)
                val += 0xffff;

            val >>= 2;
#ifndef IRISGL
            /* set alpha to 0 for openGL */
            val &= 0xfff0;
#endif

            /* Set all 4 quadrants to val */
            image[(SPOT_SIZE / 2 - i) * SPOT_SIZE + (SPOT_SIZE / 2 - j)] =
                image[(SPOT_SIZE / 2 - i) * SPOT_SIZE + (SPOT_SIZE / 2 + j)] =
                image[(SPOT_SIZE / 2 + i) * SPOT_SIZE + (SPOT_SIZE / 2 + j)] =
                image[(SPOT_SIZE / 2 + i) * SPOT_SIZE + (SPOT_SIZE / 2 - j)] =
                (unsigned short) val;

        }
    }

    tex = pfNewTex(pfGetSharedArena());
    pfTexImage(tex, (uint*) image, 2, SPOT_SIZE, SPOT_SIZE, 0);
    pfTexFormat(tex, PFTEX_INTERNAL_FORMAT, PFTEX_IA_8);
    pfTexRepeat(tex, PFTEX_WRAP, PFTEX_CLAMP);

    /*
        pfSaveTexFile(tex, "myspot.tex");
    */
    return tex;
}

#define FOV 45.0f
#define NEAR 1.0f
#define SQRT2INV .7071067811865475244

static pfDCS *shadDCS, *projDCS, *proj2DCS;
static pfLightSource *shad, *proj, *proj2;

static pfGroup*
initLSources(pfSphere *bsphere)
{
    pfFrustum *shadFrust;
    pfTexture *tex;
    pfGroup *group;
    float d;
    pfMatrix mat;
    void *arena = pfGetSharedArena();

    /* Create and configure shadow frustum. Fit frustum tightly to scene. */
    shadFrust = pfNewFrust(arena);
     
    pfMakeSimpleFrust(shadFrust, FOV);

    d = bsphere->radius / sinf(PF_DEG2RAD(FOV/2.0f));
    d = PF_MAX2(d, NEAR + bsphere->radius);

    pfFrustNearFar(shadFrust, NEAR, d + 1.1f * bsphere->radius);

    if (enable_shadows)
    {
            /* Create and configure white shadow casting light source */
            shad = pfNewLSource();
            pfLSourceMode(shad, PFLS_SHADOW_ENABLE, 1);
            pfLSourceAttr(shad, PFLS_PROJ_FRUST, shadFrust);
            pfLSourceColor(shad, PFLT_DIFFUSE, 1.0f, 1.0f, 1.0f);
            pfLSourceVal(shad, PFLS_INTENSITY, .2f); /* shadow not complety dark */
            pfLSourcePos(shad, 0.0f, 0.0f, 0.0f, 1.0f); /* Make light local */
        pfLSourceVal(shad, PFLS_SHADOW_SIZE, SPOT_SIZE);
    }

    /* Create and configure blue spotlight */
    proj = pfNewLSource();
    if (SpotTexture)
        tex = initSpotTex();
    else
    {
       tex = pfNewTex(arena);
       pfLoadTexFile(tex, "myspot.tex");
       pfTexRepeat(tex, PFTEX_WRAP, PFTEX_CLAMP);
    }

    pfLSourceMode(proj, PFLS_PROJTEX_ENABLE, 1);
    pfLSourceAttr(proj, PFLS_PROJ_FRUST, shadFrust);
    pfLSourceAttr(proj, PFLS_PROJ_TEX, tex);
    if (Whites)
       pfLSourceColor(proj, PFLT_DIFFUSE, 1.0f, 1.0f, 1.0f);
    else
       pfLSourceColor(proj, PFLT_DIFFUSE, 0.0f, 0.0f, 1.0f);

    pfLSourceVal(proj, PFLS_INTENSITY, 0.5f);
    pfLSourcePos(proj, 0.0f, 0.0f, 0.0f, 1.0f); /* Make light local */

    group = pfNewGroup();

    /* Make DCSes to move lights around */
    if (enable_shadows)
    {

            shadDCS = pfNewDCS();

            pfMakeTransMat(mat, d*SQRT2INV, 0.0f, d*SQRT2INV);
            pfDCSMat(shadDCS, mat);
            lookAt(shadDCS, bsphere->center);

            pfAddChild(shadDCS, shad);
        if (Shadow)
                pfAddChild(group, shadDCS);
    }

    projDCS = pfNewDCS();

    pfMakeTransMat(mat, -d*SQRT2INV, 0.0f, d*SQRT2INV);
    pfDCSMat(projDCS, mat);
    lookAt(projDCS, bsphere->center);

    pfAddChild(projDCS, proj);
    if (SpotOne)
        pfAddChild(group, projDCS);
    if (SpotTwo)
    {
        /* Create and configure red spotlight */
        proj2 = pfNewLSource();
        pfLSourceMode(proj2, PFLS_PROJTEX_ENABLE, 1);
        pfLSourceAttr(proj2, PFLS_PROJ_FRUST, shadFrust);
        pfLSourceAttr(proj2, PFLS_PROJ_TEX, tex);
        if (Whites)
            pfLSourceColor(proj2, PFLT_DIFFUSE, 1.0f, 1.0f, 1.0f);
        else
            pfLSourceColor(proj2, PFLT_DIFFUSE, 1.0f, 0.0f, 0.0f);
        pfLSourceVal(proj2, PFLS_INTENSITY, .5f);
        pfLSourcePos(proj2, 0.0f, 0.0f, 0.0f, 1.0f); /* Make light local */

        proj2DCS = pfNewDCS();
        pfMakeTransMat(mat, d*SQRT2INV, 0.0f , d*SQRT2INV);
        pfDCSMat(proj2DCS, mat);
        lookAt(proj2DCS, bsphere->center);
        pfAddChild(proj2DCS, proj2);
        pfAddChild(group,proj2DCS);
    }
    /* Add a regular white light */
    if (Ambient)
        pfAddChild(group, pfNewLSource());

    return group;
}

static pfGeode*
initFloor(pfSphere *bsphere)
{
    pfGeoSet *gset;
    pfGeoState *gstate;
    pfGeode *geode;
    pfVec4 *c;
    pfVec3 *v;
    pfMaterial *mtl;
    float d;
    void *arena = pfGetSharedArena();
    pfVec2 *t;
    pfTexture *tex;
    pfTexEnv *tev;

    gset = pfNewGSet(arena);
    gstate = pfNewGState(arena);
    geode = pfNewGeode();
     
    v = (pfVec3*)pfMalloc(sizeof(pfVec3) * 4, arena);
    d = 1.7f * bsphere->radius;

    pfSetVec3(v[0], -d, -d, -d/3.0f);
    pfSetVec3(v[1], d, -d, -d/3.0f);
    pfSetVec3(v[2], d, d, -d/3.0f);
    pfSetVec3(v[3], -d, d, -d/3.0f);
    pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, v, NULL);

    v = (pfVec3*)pfMalloc(sizeof(pfVec3), arena);
    pfSetVec3(v[0], 0.0f, 0.0f, 1.0f);
    pfGSetAttr(gset, PFGS_NORMAL3, PFGS_OVERALL, v, NULL);

    if (Floor)
    {
        t = (pfVec2*) pfMalloc(sizeof(pfVec2) *4, pfGetSharedArena());
        t[0][0] = 0.; t[0][1] = 0.;
        t[1][0] = 1.; t[1][1] = 0.;
        t[2][0] = 1.; t[2][1] = 1.;
        t[3][0] = 0.; t[3][1] = 1.;
         
        pfGSetAttr(gset, PFGS_TEXCOORD2, PFGS_PER_VERTEX, t, NULL);
    }
     else
    {

        c = (pfVec4*) pfMalloc(sizeof(pfVec4) , pfGetSharedArena());
  
        c[0][0] = 0.7;
        c[0][1] = 0.7;
        c[0][2] = 0.7;
        c[0][3] = 1.;
  
        pfGSetAttr(gset, PFGS_COLOR4, PFGS_OVERALL, c, NULL);
    }

    pfGSetPrimType(gset, PFGS_QUADS);
    pfGSetNumPrims(gset, 1);

    if (Floor)
    {
        tex = pfNewTex(pfGetSharedArena());
        pfLoadTexFile(tex,"floor5.rgb");

        pfTexFormat(tex,PFTEX_INTERNAL_FORMAT, PFTEX_RGB_8);
        pfTexRepeat(tex,PFTEX_WRAP, PFTEX_REPEAT);
        
        pfGStateAttr(gstate, PFSTATE_TEXTURE, tex);
        pfGStateMode(gstate, PFSTATE_ENTEXTURE, 1);

        tev = pfNewTEnv(pfGetSharedArena());

        pfTEnvMode(tev, PFTE_DECAL);
        pfGStateAttr(gstate,PFSTATE_TEXENV, tev);

        mtl = pfNewMtl(arena);
        pfMtlColorMode(mtl, PFMTL_BOTH, PFMTL_CMODE_OFF);
        pfMtlColor(mtl,PFMTL_AMBIENT, 0.7, 0.7, 0.7);
        pfGStateAttr(gstate, PFSTATE_FRONTMTL, mtl);
        pfGStateMode(gstate, PFSTATE_ENLIGHTING, 1);
    }

    pfGSetGState(gset, gstate);
    pfAddGSet(geode, gset);

    return geode;
}

int
main (int argc, char *argv[])
{
    int loop;
     
    pfScene *scene;
    pfNode *root;
    pfDCS *dcs;
    pfPipe *p;
    pfPipeWindow *pw;
    pfChannel *chan;
    pfSphere bsphere;
    pfCoord view;
    pfMatrix mat, orbit1, orbit2, orbit3;
    pfList *texList;
    int ret;
    int arg = 1;
    int found;

    if (argc < 2)
        Usage();
    if (argc == 2)
        Default();
    else
        arg = docmdline(argc,argv);

    /* Initialize Performer */
    pfInit();

    pfQueryFeature(PFQFTR_TEXTURE_PROJECTIVE, &ret);
    if (!(ret == PFQFTR_FAST))
    {
        printf("Sorry, Projected Light Sources are not supported \n");
        return 0;
    }

    if (Shadow)
    {
        pfQueryFeature(PFQFTR_TEXTURE_SHADOW, &ret);
        if (!(ret == PFQFTR_FAST))
        {
            printf("Sorry, Shadow are not supported !\n");
            enable_shadows = 0;
        }
    } else
    enable_shadows = 0;

    /* Use default multiprocessing mode based on number of
     * processors.
     */
    pfMultiprocess(PFMP_DEFAULT);

    /* Load all loader DSO's before pfConfig() forks */
    for (found = arg; found < argc; found++)
        pfdInitConverter(argv[found]);

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

    /* Append to PFPATH additional standard directories where
     * geometry and textures exist
     */
    pfFilePath(".:/usr/share/Performer/data");

    /* Do not use FLAT_ primitives because they look bad
     * with local lighting.
    */
    pfdBldrMode(PFDBLDR_MESH_LOCAL_LIGHTING, 1);

    /* load files named by command line arguments */
    scene = pfNewScene();
    dcs = pfNewDCS();
    pfMakeRotMat(mat, 30.0f, 1.0f, 0.0f, 0.0f);
    pfDCSMat(dcs, mat);
    pfAddChild(scene, dcs);

    for (found = 0; arg < argc; arg++)
    {
        if ((root = pfdLoadFile(argv[arg])) != NULL)
        {
            pfAddChild(dcs, root);
            found++;
        }
    }

    if (!found)
    {
        pfNotify(PFNFY_FATAL,PFNFY_USAGE,"Error loading database files");
        exit(-1);
    }

    /* determine extent of scene's geometry */
    pfGetNodeBSphere (scene, &bsphere);

    /* Create pfLightSources and add to scene */
    pfAddChild(scene, initLSources(&bsphere));

    /* Create "floor" for shadows */
    pfAddChild(dcs, initFloor(&bsphere));

    /* Configure and open GL window */
    p = pfGetPipe(0);
    pw = pfNewPWin(p);
    pfPWinName(pw, argv[0]);
    pfPWinConfigFunc(pw, OpenPipeWin);
    pfPWinOriginSize(pw, 0, 0, 500, 500);
    pfPWinType(pw, PFPWIN_TYPE_X);
    pfPWinFBConfigAttrs(pw, FBAttrs);
    pfConfigPWin(pw);

    /* Create and configure a pfChannel. */
    chan = pfNewChan(p);
    pfChanScene(chan, scene);
    pfChanNearFar(chan, 1.0f, 5.0f * bsphere.radius);
    pfChanFOV(chan, 45.0f, 0.0f);
    pfCopyVec3(view.xyz, bsphere.center);
    view.xyz[PF_Y] -= 3.0f * bsphere.radius;
    pfSetVec3(view.hpr, 0.0f, 0.0f, 0.0f);
    pfChanView(chan, view.xyz, view.hpr);
    pfChanTravFunc(chan, PFTRAV_DRAW, DrawChannel);

    /* If scene is non-textured then we can save an entire rendering pass */
    texList = pfuMakeSceneTexList(scene);
    if (pfGetNum(texList) == 0)
    {
        pfChanTravMode(chan, PFTRAV_MULTIPASS, PFMPASS_NONTEX_SCENE);
        pfNotify(PFNFY_NOTICE, PFNFY_PRINT,
                 "Scene is non-textured! Using PFMPASS_NONTEX_SCENE "
                 "optimization");
    }

    pfMakeRotMat(orbit1, 1.3f, 0.0f, 0.0f, 1.0f);
    pfMakeRotMat(orbit2, 0.7f, 0.0f, 0.0f, 1.0f);
    pfMakeRotMat(orbit3, -1.2f, 0.f, 0.0f, 1.0f);

    /* Simulate for ever ! */
    loop = 0;
    while (1)
    {
        loop ++;
        /* Spin light sources around object */
        if (SpotOne)
        {
            pfMultMat(mat, *pfGetDCSMatPtr(projDCS), orbit1);
            pfDCSMat(projDCS, mat);
            lookAt(projDCS, bsphere.center);
        }
        if (SpotTwo)
        {
            pfMultMat(mat, *pfGetDCSMatPtr(proj2DCS), orbit2);
            pfDCSMat(proj2DCS, mat);
            lookAt(proj2DCS, bsphere.center);
        }
        if (enable_shadows)
        {
                pfMultMat(mat, *pfGetDCSMatPtr(shadDCS), orbit3);
                pfDCSMat(shadDCS, mat);
                lookAt(shadDCS, bsphere.center);
        }

        /* Initiate cull/draw for this frame. */
        pfFrame();
#ifndef IRISGL
   {
   int err;
   if ((err = glGetError()) != GL_NO_ERROR)
        pfNotify(PFNFY_NOTICE,PFNFY_USAGE,"OpenGL Error 0x%x - %s",err, gluErrorString(err));
   }
#endif /* GL Type */

    }

    /* press Ctrl-C to exit ! */
}


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Tue Sep 29 1998 - 13:21:26 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.