home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / inventorTemplates / player.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  15.5 KB  |  651 lines

  1. /*
  2.  * Copyright 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  * Copyright (C) 1992   Silicon Graphics, Inc.
  19.  *
  20.  _______________________________________________________________________
  21.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  22.  |
  23.  |   $Revision: 1.0000 $
  24.  |
  25.  |   File: player.c++
  26.  |   Purpose: opens a gl window, and creates and animation based upon
  27.  |            the inventor models and animation file input
  28.  |
  29.  |   Author(s)          : Kevin Goldsmith
  30.  |
  31.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  32.  _______________________________________________________________________
  33.  */
  34.  
  35.  
  36.  
  37.  
  38. #include <string.h>
  39. #include <unistd.h>
  40. #include <getopt.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43.  
  44. #include <Inventor/SoDB.h>
  45. #include <Inventor/Xt/SoXt.h>
  46. #include <Inventor/Xt/SoXtRenderArea.h>
  47. #include <Inventor/nodes/SoSeparator.h>
  48. #include <Inventor/nodes/SoPerspectiveCamera.h>
  49. #include <Inventor/nodes/SoPointLight.h>
  50. #include <Inventor/nodes/SoLabel.h>
  51. #include <Inventor/actions/SoWriteAction.h>
  52. #include <Inventor/actions/SoSearchAction.h>
  53. #include <Inventor/SbLinear.h>
  54. #include <Inventor/SoOffscreenRenderer.h>
  55.  
  56. #define MAX_KEY_FRAMES 20
  57.  
  58. // these are global variables for some important stuff
  59. static char *filename = NULL;
  60. static char *animfile = NULL;
  61.  
  62. // these are globals for flags and stuff
  63. static int saveNum; // saves the start frame #
  64. static int save = 0; // says if we are saving to disk or not
  65. static int frameNum; // current frame number
  66. static int currentkey; // current keyframe number
  67. static int printenv = 0; // do we print out an env file when done?
  68. static int startFrame = 0; // the start frame
  69. static int endFrame = 0; // the end frame
  70. static int START = 0; // did the user give us a start frame?
  71. static int END = 0;   // did the user give us an end frame?
  72. static int camLinear = 0; // are we linearly interpolating?
  73. static int verbose = 0; // are we chatty?
  74. static int xwidth = 640; // width of the screen
  75. static int yheight = 480; // height of the screen
  76. static int naptime = 0;
  77.  
  78. // structure for splines
  79. typedef struct {
  80.   double min_x, max_x;        /* min and max domain points */
  81.   long n;            /* number of domain points */
  82.   double *x;            /* array of domain points */
  83.   double *a;            /* spline coefficients */
  84.   double *b;
  85.   double *c;
  86.   double *d;
  87. } SPLINE;
  88.  
  89. // global splines for camera movement
  90. SPLINE *PosSplineX;
  91. SPLINE *PosSplineY;
  92. SPLINE *PosSplineZ;
  93.  
  94. //key frame structure
  95. struct keyframe {
  96.     int frame;
  97.     SbVec3f position;
  98.     SbVec3f axis;
  99.     float angle;
  100. } keyFrames[MAX_KEY_FRAMES];
  101.  
  102. // global number of keyframes
  103. int keyframenum;
  104.  
  105.  
  106.  
  107. //
  108. // FILE READING STUFF!!!
  109. //
  110.  
  111.  
  112. // better way to open a file
  113. static FILE *OPEN(const char *filename, char *type)
  114. {
  115.     FILE *fp;
  116.     if ((fp = fopen(filename, type)) == NULL) {
  117.     fprintf(stderr, "Couldn't open %s\n", filename);
  118.     exit(1);
  119.     }
  120.     return fp;
  121. }
  122.  
  123.  
  124. // reads in the animation file, not very smart, will not check for errors
  125. void readFile(const char *animfile)
  126. {
  127.     FILE *fp;
  128.     int tempframe;
  129.     float temp[7];
  130.  
  131.     keyframenum = 0;
  132.     fp = OPEN (animfile, "r");
  133.     while(1) {
  134.     if (fscanf(fp, "%d %f %f %f %f %f %f %f", &tempframe, &temp[0],
  135.            &temp[1], &temp[2], &temp[3], &temp[4], &temp[5],
  136.            &temp[6]) == EOF)
  137.       break;
  138.     keyFrames[keyframenum].frame = tempframe;
  139.     keyFrames[keyframenum].position = SbVec3f(temp[0], temp[1], temp[2]);
  140.     keyFrames[keyframenum].axis = SbVec3f(temp[3], temp[4], temp[5]);
  141.     keyFrames[keyframenum].angle = temp[6];
  142.     ++keyframenum;
  143.     }
  144.     fclose(fp);
  145.     if (verbose) fprintf(stderr, "%d keyframes read\n", keyframenum);
  146. }
  147.  
  148.  
  149. //
  150. // Read a file given a filename and return a separator containing all
  151. // of the stuff in the file.
  152. // stolen mostly from Gavin Bell
  153. //
  154. SoSeparator *
  155. readivFile(const char *filename)
  156. {
  157.     SoInput in;
  158.     if (filename != NULL)
  159.     {
  160.     if (in.openFile(filename) == FALSE)
  161.     {
  162.         fprintf(stderr, "Could not open file %s\n", filename);
  163.         return NULL;
  164.     }
  165.     }
  166.  
  167.     SoSeparator *graph = new SoSeparator;
  168.     graph->ref();
  169.  
  170.     //
  171.     // Keep on reading until there are no more nodes to read
  172.     //
  173.     SoNode *root;
  174.     do
  175.     {
  176.     int read_ok = SoDB::read(&in, root);
  177.  
  178.     if (!read_ok)
  179.     {
  180.         fprintf(stderr, "Error reading file\n");
  181.         graph->unref();
  182.         return NULL;
  183.     }
  184.     else if (root != NULL) graph->addChild(root);
  185.  
  186.     } while (root != NULL);
  187.     in.closeFile();
  188.  
  189.     //
  190.     // Try to avoid creating extra separators; if this scene graph
  191.     // already has exactly one separator at the top, use it.  This
  192.     // will avoid an explosion of separators at the top of scenes that
  193.     // would otherwise occur if we automatically created a new
  194.     // separator every time a scene graph was read.
  195.     //
  196.     if (graph->getNumChildren() == 1 &&
  197.     graph->getChild(0)->isOfType(SoSeparator::getClassTypeId()))
  198.     {
  199.     SoSeparator *result = (SoSeparator *)graph->getChild(0);
  200.     result->ref();    // Note the order here!
  201.     graph->unref();
  202.  
  203.     result->unrefNoDelete();
  204.     return result;
  205.     }
  206.  
  207.     graph->unrefNoDelete();
  208.     return graph;
  209.  
  210. }
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220. //
  221. // SPLINE STUFF!!!!!
  222. // I stole these mostly from Drew Olbrich
  223. //
  224.  
  225. SPLINE *spline_new(int n, double *x, double *f)
  226. {
  227.   SPLINE *spline;
  228.   int i;
  229.   double t;
  230.   double *h;
  231.   double *u;
  232.   double *ta;
  233.   double *td;
  234.   double *tb;
  235.   double *tf;
  236.  
  237.   if (n < 3)
  238.     return NULL;
  239.  
  240.   spline = (SPLINE *) malloc(sizeof(SPLINE));
  241.   if (spline == NULL) 
  242.   {
  243.     fprintf(stderr, "Could not allocate spline.\n");
  244.     exit(-1);
  245.   }
  246.  
  247.   spline->x = (double *) malloc((n*sizeof(double)));
  248.   if (spline->x == NULL) 
  249.   {
  250.     fprintf(stderr, "Could not allocate spline data.\n");
  251.     exit(-1);
  252.   }
  253.   for (i = 0; i < n; i++)
  254.     spline->x[i] = x[i];
  255.  
  256.   spline->n = n;
  257.   spline->min_x = x[0];
  258.   spline->max_x = x[n - 1];
  259.  
  260.   spline->a = (double *) malloc(n*sizeof(double));
  261.   spline->b = (double *) malloc(n*sizeof(double));
  262.   spline->c = (double *) malloc(n*sizeof(double));
  263.   spline->d = (double *) malloc(n*sizeof(double));
  264.  
  265.   if (spline->d == NULL)
  266.   {
  267.     fprintf(stderr, "Could not allocate spline coefficient data.\n");
  268.     exit(-1);
  269.   }
  270.  
  271.   h = (double *) malloc((n+1)*sizeof(double));
  272.   u = (double *) malloc((n+1)*sizeof(double));
  273.  
  274.   ta = (double *) malloc((n+1)*sizeof(double));
  275.   td = (double *) malloc((n+1)*sizeof(double));
  276.   tb = (double *) malloc((n+1)*sizeof(double));
  277.   tf = (double *) malloc((n+1)*sizeof(double));
  278.  
  279.   if (tf == NULL)
  280.   {
  281.     fprintf(stderr, "Could not allocate temporary spline data.\n");
  282.     exit(-1);
  283.   }
  284.  
  285.   for (i = 0; i < n - 1; i++) {
  286.     h[i] = x[i + 1] - x[i];
  287.     u[i] = (f[i + 1] - f[i])/h[i];
  288.     spline->a[i] = f[i];
  289.   }
  290.  
  291.   for (i = 0; i < (n - 2); i++)
  292.     td[i] = 2.0*(h[i] + h[i + 1]);
  293.  
  294.   for (i = 0; i < (n - 2); i++)
  295.     ta[i] = tb[i] = h[i + 1];
  296.  
  297.   for (i = 0; i < (n - 2); i++)
  298.     tf[i] = 3.0*(u[i + 1] - u[i]);
  299.  
  300.   for (i = 1; i < (n - 2); i++)
  301.   {
  302.     t = ta[i - 1]/td[i - 1];
  303.     td[i] = td[i] - t*tb[i - 1];
  304.     tf[i] = tf[i] - t*tf[i - 1];
  305.   }
  306.  
  307.   spline->c[0] = 0.0;
  308.   spline->c[n - 1] = 0.0;
  309.   spline->c[n - 2] = tf[n - 3]/td[n - 3];
  310.   for (i = (n - 4); i >= 0; i--)
  311.     spline->c[i + 1] = (tf[i] - tb[i]*spline->c[i + 2])/td[i];
  312.  
  313.   for (i = 0; i < (n - 1); i++) {
  314.     spline->b[i] = u[i] - h[i]*(2.0*spline->c[i] + spline->c[i + 1])/3.0;
  315.     spline->d[i] = (spline->c[i + 1] - spline->c[i])/(h[i]*3.0);
  316.   }
  317.  
  318.   free(h);
  319.   free(u);
  320.  
  321.   free(ta);
  322.   free(td);
  323.   free(tb);
  324.   free(tf);
  325.  
  326.   return spline;
  327. }
  328.  
  329.  
  330.  
  331. double spline_eval(SPLINE *spline, double t)
  332. {
  333.   int i;
  334.   int high, low, mid;
  335.   double result, qq;
  336.  
  337.   if (spline == NULL)
  338.     return 0.0;
  339.  
  340.   if ((t < spline->min_x) || (t > spline->max_x))
  341.     return 0.0;
  342.  
  343.   low = 0;
  344.   high = (int) spline->n - 1;
  345.   i = -1;
  346.   while (i == -1 && low <= high) {
  347.     mid = (low + high) >> 1;
  348.     if (t < spline->x[mid])
  349.       high = mid - 1;
  350.     else if (mid + 1 < spline->n && t > spline->x[mid + 1])
  351.       low = mid + 1;
  352.     else
  353.       i = mid;
  354.   }
  355.   qq = t - spline->x[i];
  356.  
  357.   result = spline->a[i]    
  358.     + qq*(spline->b[i] + qq*(spline->c[i] + qq*spline->d[i]));
  359.   
  360.   return result;
  361. }
  362.  
  363. // creates the splines for the animation
  364. void
  365. createSplines()
  366. {
  367.     double a[MAX_KEY_FRAMES], x[MAX_KEY_FRAMES],
  368.            y[MAX_KEY_FRAMES], z[MAX_KEY_FRAMES];
  369.     float tempx, tempy, tempz;
  370.  
  371.     for (int i = 0; i < keyframenum; i++) {
  372.     a[i] = (double) keyFrames[i].frame;
  373.     keyFrames[i].position.getValue(tempx, tempy, tempz);
  374.     x[i] = (double) tempx;
  375.     y[i] = (double) tempy;
  376.     z[i] = (double) tempz;
  377.     }
  378.     
  379.      PosSplineX = spline_new(keyframenum, a, x);
  380.      PosSplineY = spline_new(keyframenum, a, y);
  381.      PosSplineZ = spline_new(keyframenum, a, z);
  382. }
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394. // this is where the light and the camera are updated
  395. void Animate(SoCamera *camera, SoPointLight *light)
  396. {
  397.     if (verbose) fprintf(stderr, "rendering frame #%d: ",frameNum);
  398.  
  399.     if (!camLinear) {
  400.     // if we are using splines
  401.     camera->position = SbVec3f((float) spline_eval(PosSplineX,frameNum),
  402.                    (float) spline_eval(PosSplineY,frameNum),
  403.                    (float) spline_eval(PosSplineZ,frameNum));
  404.     } else {
  405.     // otherwise
  406.     float t = (float) (frameNum - keyFrames[currentkey].frame) /
  407.       (float) (keyFrames[currentkey + 1].frame -
  408.             keyFrames[currentkey].frame);
  409.     float x,y,z,x2,y2,z2;
  410.  
  411.     keyFrames[currentkey].position.getValue(x,y,z);
  412.     keyFrames[currentkey + 1].position.getValue(x2,y2,z2);
  413.     camera->position = SbVec3f((x + t * (x2 - x)),
  414.                    (y + t * (y2 - y)),
  415.                    (z + t * (z2 - z)));
  416.     }
  417.     
  418.     light->location = camera->position;
  419.     // to be easy, I am just using a pointlight as a headlight, and
  420.     // having it be in the exact same place as the camera.
  421.     // things would work faster, if I was using a directional light
  422.     // facing in the same direction as the camera
  423.  
  424.  
  425.     // are we up to the next keyframe?
  426.     if (keyFrames[currentkey + 1].frame <= frameNum) currentkey++;
  427.  
  428.  
  429.     if (currentkey < keyframenum - 1) {
  430.     // dont bother if we are done
  431.  
  432.     SbRotation last, next;
  433.     float t;
  434.  
  435.     last = SbRotation(keyFrames[currentkey].axis,
  436.               keyFrames[currentkey].angle);
  437.     next = SbRotation(keyFrames[currentkey+1].axis,
  438.               keyFrames[currentkey+1].angle);
  439.     t = (float) (frameNum - keyFrames[currentkey].frame) /
  440.         (float) (keyFrames[currentkey + 1].frame
  441.              - keyFrames[currentkey].frame);
  442.  
  443.     camera->orientation.setValue(SbRotation::slerp(last, next, t));
  444.     }
  445.  
  446.     ++frameNum; // move onto the next frame
  447. }
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454. // parses the command line for user stuff
  455. static void
  456. parseCommandLine(int argc, char **argv)
  457. {
  458.     int err = 0;    // Flag: error in options?
  459.     int c;
  460.  
  461.     while (( c = getopt(argc, argv, "ls:e:pq:vx:y:n:")) != -1)
  462.       {
  463.       switch(c)
  464.         {
  465.         case 'l':
  466.         camLinear = 1;
  467.         break;
  468.           case 's':
  469.         START = 1;
  470.         startFrame = atoi(optarg);
  471.         break;
  472.           case 'e':
  473.         END = 1;
  474.         endFrame = atoi(optarg);
  475.         break;
  476.           case 'p':
  477.         printenv = 1;
  478.         fprintf(stderr, "printing out env file at end\n");
  479.         break;
  480.           case 'q':
  481.         saveNum = atoi(optarg);
  482.         save = 1;
  483.         break;
  484.             case 'v':
  485.         verbose = 1;
  486.         break;
  487.           case 'x':
  488.         xwidth = atoi(optarg);
  489.         break;
  490.           case 'y':
  491.         yheight = atoi(optarg);
  492.         break;
  493.             case 'n':
  494.         naptime = atoi(optarg);
  495.         break;
  496.           default:
  497.         err = 1;
  498.         break;
  499.         }
  500.       
  501.       }
  502.  
  503.     if (optind+2 != argc) err = 1;
  504.  
  505.     filename = argv[optind];
  506.     animfile = argv[optind + 1];
  507.  
  508.     if (err)
  509.     {
  510.     fprintf(stderr, "Usage: %s [-p] [-v] [-q num] [-l] [-s start]",
  511.         " [-e end] [-x width] [-y height] [-n clicks]",
  512.         " inventorfilename animationfilename\n",
  513.         argv[0]);
  514.     fprintf(stderr, "-p prints out an environment file at the end of animation\n");
  515.     fprintf(stderr, "-v turns on verbose mode\n");
  516.     fprintf(stderr, "-q saves the animation starting at frame num\n");
  517.     fprintf(stderr, "-l moves the camera linearly between control points\n");
  518.     fprintf(stderr, "-s starts the animation at frame num\n");
  519.     fprintf(stderr, "-e ends the animation at frame num\n");
  520.     fprintf(stderr, "-x set the width of the animation\n");
  521.     fprintf(stderr, "-y set the height of the animation\n");
  522.     fprintf(stderr, "-n set the ammount of ticks pausing between frames\n");
  523.     exit(99);
  524.     }
  525. }
  526.  
  527.  
  528. //
  529. // at last we made it to MAIN
  530. //
  531. main( int argc, char **argv )
  532. {
  533.     SoCamera *camera = NULL;
  534.     SoPointLight *light = NULL;
  535.  
  536.     parseCommandLine(argc, argv);
  537.  
  538.     // set up the window and database for our purposes
  539.     // a lot of GL could be avoid through inventor, but its good to show as
  540.     // an example
  541.     Widget mainWindow = SoXt::init(argv[0]);
  542.     if (mainWindow == NULL) {
  543.     fprintf(stderr, "error initing SoXt\n");
  544.     exit(1);
  545.     }
  546.  
  547.     // create the root of the scenegraph
  548.     SoSeparator *root = new SoSeparator;
  549.     root->ref();
  550.  
  551.     // create the camera
  552.     camera = new SoPerspectiveCamera;
  553.     camera->ref();
  554.     camera->farDistance = 100;
  555.     camera->nearDistance = 0.0001;
  556.     root->insertChild(camera, 0);
  557.  
  558.     // create our wuss version of a headlight
  559.     light = new SoPointLight;
  560.     root->insertChild(light, 1);
  561.  
  562.     // read in the scenegraph from a file
  563.     SoSeparator *stuff = readivFile(filename);
  564.     if (stuff == NULL) exit(1); // did not get a scenegraph
  565.     root->addChild(stuff);
  566.  
  567.     readFile(animfile); // read in the animation file
  568.     createSplines(); // create the splines
  569.  
  570.     // if we are not starting at the first frame, we have to figure out
  571.     // which key frames we are between
  572.     currentkey = 0;
  573.     if (START) {
  574.       frameNum = startFrame;
  575.       for (int i = 0; i < keyframenum; i++) {
  576.       if (keyFrames[currentkey + 1].frame <= frameNum) currentkey++;
  577.       }
  578.     } else {
  579.     frameNum = 0; // starting at the begining
  580.     }
  581.  
  582.     // create the Viewer
  583.     SoXtRenderArea *rendArea = new SoXtRenderArea(mainWindow);
  584.     rendArea->setAutoRedraw(FALSE);
  585.     rendArea->setSceneGraph(root);    
  586.     rendArea->setTitle(argv[0]);
  587.     rendArea->setSize(SbVec2s(xwidth, yheight));
  588.     rendArea->show();
  589.     SoXt::show(mainWindow);
  590.  
  591.     SbViewportRegion offViewport(xwidth, yheight);
  592.     SoOffscreenRenderer *offrender = new SoOffscreenRenderer(offViewport);
  593.     FILE *fp;
  594.  
  595.     XtAppContext context = SoXt::getAppContext();
  596.     XEvent event;
  597.  
  598.     // this is the mother of all rendering loops
  599.     while ( 1 ) {
  600.     while(XtAppPending(context)) {
  601.         SoXt::nextEvent(context, &event);
  602.         SoXt::dispatchEvent(&event);
  603.     }
  604.  
  605.     Animate(camera, light); // move the camera and the light
  606.     rendArea->render();
  607.  
  608.     // if we are done, get out of the loop
  609.     if ((currentkey == keyframenum - 1 ) || (END && (frameNum > endFrame)))
  610.       break;
  611.  
  612.     // if we are saving the screen, do it
  613.     if (save) {
  614.         char filename[100];
  615.         char num[10];
  616.         int frame;
  617.  
  618.         frame = frameNum + saveNum -1;
  619.         if (frame < 10)
  620.           sprintf(num, "00%d", frame);
  621.         else
  622.           if (frame < 100)
  623.         sprintf(num, "0%d", frame);
  624.           else
  625.         sprintf(num, "%d", frame);
  626.  
  627.         sprintf(filename, "animation%s.rgb", num);
  628.         if (verbose) fprintf(stderr, " saving screen %d", frame);
  629.  
  630.         offrender->render(root);
  631.         fp = OPEN(filename, "w");
  632.         offrender->writeToRGB(fp);
  633.         fclose(fp);
  634.     } else {
  635.         // pause, or it will go too fast
  636.         sginap(naptime);
  637.     }
  638.  
  639.     if (verbose) fprintf(stderr, "\n");
  640.  
  641.     }
  642.  
  643.     // if the user wanted us to print out the env file at the end
  644.     if (printenv) {
  645.     SoWriteAction wa;
  646.     wa.apply(camera);
  647.     }
  648.  
  649.     if (verbose) fprintf(stderr, "\n");
  650. }
  651.