home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / Wave / WavesWorld / Source / IBPalettes / WW3DKit / WW3DCamera.m < prev    next >
Encoding:
Text File  |  1995-05-17  |  171.7 KB  |  5,319 lines

  1. // copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
  2. // see COPYRIGHT for reuse legalities
  3. //
  4.  
  5. #import "WW3DCamera.h"
  6.  
  7. #import "WWInterp.h" // this includes WWTCLKit.h 
  8.  
  9. #import "WW3DShape.h"
  10. #import "WW3DShader.h"
  11. #import "WW3DText.h"
  12. #import "RIBColor.h"
  13. #import "RIBTorus.h"
  14. #import "WW3DLight.h"
  15.  
  16. #import "WW3DWell.h"
  17. #import "WWSceneClock.h"  // has the sceneClock protocol - formalize this!
  18. #import "WWEveParser.h"  // to work around NeXT's copyRIB: bug...
  19.  
  20. #import <mach/cthreads.h>
  21.  
  22. @implementation WW3DCamera
  23.  
  24. + initialize { return [WW3DCamera setVersion:5], self; }
  25.  
  26. static char errBuf[1024]; 
  27.  
  28. /*
  29. ==========================================================================
  30. subext() -- Remove extension from fname only if it is there.
  31.  
  32. ==========================================================================
  33. */
  34. static char 
  35. *subext(fname, ext)
  36. register char *fname, *ext;
  37. {
  38.   int fl, el;
  39.  
  40.     for ( fl = strlen(fname), el = strlen(ext);
  41.         --el > -1 && --fl > -1 && fname[fl] == ext[el]; )
  42.         ;
  43.     if (el == -1) 
  44.     {  fname[fl] = '\0';
  45.     }
  46.     return(fname);
  47. }
  48.  
  49.  
  50. /*
  51. ==========================================================================
  52. basename() -- deletes any prefix ending in `/' and the suffix.
  53.  
  54. ==========================================================================
  55. */
  56. static char 
  57. *basename(str, sfx, dest)
  58. char *str, *sfx, *dest;
  59. {
  60. char temp[1024];
  61. char *p, *p1;
  62. char *subext();
  63.  
  64.     p = p1 = temp;
  65.     strcpy(p, str);
  66.     while (*p) 
  67.     {  if (*p++ == '/') 
  68.            {  p1 = p;
  69.        }
  70.     }
  71.     strcpy (dest, subext(p1, sfx));
  72.     return(dest);
  73. }
  74.  
  75.  
  76. static int
  77. cmd_dumpRIBToFile(me, interp, argc, argv)
  78. WW3DCamera *me;
  79. Tcl_Interp *interp;
  80. int argc;
  81. char **argv;
  82. {
  83.   char  *my_args = "filename";
  84.   int    num_args = 2;
  85.  
  86.  
  87.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  88.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  89.   if (argc != num_args)
  90.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  91.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  92.      return TCL_ERROR;
  93.   }
  94.  
  95.   [me dumpRIBToFile:argv[1]];
  96.  
  97.   return TCL_OK;
  98. }
  99.  
  100. static int
  101. cmd_display(me, interp, argc, argv)
  102. WW3DCamera *me;
  103. Tcl_Interp *interp;
  104. int argc;
  105. char **argv;
  106. {
  107.   char  *my_args = "";
  108.   int    num_args = 1;
  109.  
  110.  
  111.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  112.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  113.   if (argc != num_args)
  114.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  115.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  116.      return TCL_ERROR;
  117.   }
  118.  
  119.   [me display];
  120.  
  121.   return TCL_OK;
  122. }
  123.  
  124. static int
  125. cmd_backgroundColor(me, interp, argc, argv)
  126. WW3DCamera *me;
  127. Tcl_Interp *interp;
  128. int argc;
  129. char **argv;
  130. {
  131.   char     *my_args = "[{r g b}]";
  132.   NXColor  backgroundColor;
  133.   int      argc2;
  134.   char     **argv2;
  135.   float    red, green, blue;
  136.  
  137.  
  138.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  139.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  140.   if ((argc != 1) && (argc != 2) && (argc != 4))
  141.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  142.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  143.      return TCL_ERROR;
  144.   }
  145.   if (argc == 1)
  146.   {  backgroundColor = [me backgroundColor];
  147.      sprintf(interp->result, "{%f %f %f}", 
  148.          NXRedComponent(backgroundColor), 
  149.          NXGreenComponent(backgroundColor), 
  150.          NXBlueComponent(backgroundColor));
  151.      return TCL_OK;
  152.   }
  153.   if (argc == 2)
  154.   {  Tcl_SplitList(interp, argv[1], &argc2, &argv2);
  155.      if (argc2 != 3)
  156.      {  sprintf(errBuf, "USAGE: %s %s (colors should have 3 components)", argv[0], my_args);
  157.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  158.         if (argv2) { free(argv2); }
  159.     return TCL_ERROR;
  160.      }
  161.      red = (float)atof(argv2[0]);
  162.      green = (float)atof(argv2[1]);
  163.      blue = (float)atof(argv2[2]);
  164.      free(argv2);
  165.      backgroundColor = NXConvertRGBAToColor(red, green, blue, 1.0);
  166.      [me setBackgroundColor:backgroundColor];
  167.      backgroundColor = [me backgroundColor];
  168.      sprintf(interp->result, "{%f %f %f}", 
  169.          NXRedComponent(backgroundColor), 
  170.          NXGreenComponent(backgroundColor), 
  171.          NXBlueComponent(backgroundColor));
  172.      return TCL_OK;
  173.   }
  174.   if (argc == 4)
  175.   {  red = (float)atof(argv[1]);
  176.      green = (float)atof(argv[2]);
  177.      blue = (float)atof(argv[3]);
  178.      backgroundColor = NXConvertRGBAToColor(red, green, blue, 1.0);
  179.      [me setBackgroundColor:backgroundColor];
  180.      backgroundColor = [me backgroundColor];
  181.      sprintf(interp->result, "{%f %f %f}", 
  182.          NXRedComponent(backgroundColor), 
  183.          NXGreenComponent(backgroundColor), 
  184.          NXBlueComponent(backgroundColor));
  185.      return TCL_OK;
  186.   }
  187.   return TCL_ERROR;
  188. }
  189.  
  190. static int
  191. cmd_renderStyle(me, interp, argc, argv)
  192. WW3DCamera *me;
  193. Tcl_Interp *interp;
  194. int argc;
  195. char **argv;
  196. {
  197.   char  *my_args = "[PointCloud|WireFrame|ShadedWireFrame|FacetedSolids|SmoothSolids]";
  198.   int   renderStyle;
  199.  
  200.  
  201.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  202.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  203.   if ((argc != 1) && (argc != 2))
  204.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  205.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  206.      return TCL_ERROR;
  207.   }
  208.  
  209.   if (argc == 1)
  210.   {  renderStyle = [me renderStyle];
  211.      if (renderStyle == N3D_PointCloud)
  212.      {  sprintf(interp->result, "PointCloud");
  213.         return TCL_OK;
  214.      }
  215.      if (renderStyle == N3D_WireFrame)
  216.      {  sprintf(interp->result, "WireFrame");
  217.         return TCL_OK;
  218.      }
  219.      if (renderStyle == N3D_ShadedWireFrame)
  220.      {  sprintf(interp->result, "ShadedWireFrame");
  221.         return TCL_OK;
  222.      }
  223.      if (renderStyle == N3D_FacetedSolids)
  224.      {  sprintf(interp->result, "FacetedSolids");
  225.         return TCL_OK;
  226.      }
  227.      if (renderStyle == N3D_SmoothSolids)
  228.      {  sprintf(interp->result, "SmoothSolids");
  229.         return TCL_OK;
  230.      }
  231.      sprintf(interp->result, 
  232.          "Yikes! I have no mapping for renderStyle %d", 
  233.          renderStyle);
  234.      return TCL_ERROR;
  235.   }
  236.   if (argc == 2)
  237.   {  if (!strcmp(argv[1], "PointCloud"))
  238.      {  [me setRenderStyle:N3D_PointCloud];
  239.         [[me delegate] cameraParametersWereUpdated:me];
  240.         return TCL_OK;
  241.      }
  242.      if (!strcmp(argv[1], "WireFrame"))
  243.      {  [me setRenderStyle:N3D_WireFrame];
  244.         [[me delegate] cameraParametersWereUpdated:me];
  245.         return TCL_OK;
  246.      }
  247.      if (!strcmp(argv[1], "ShadedWireFrame"))
  248.      {  [me setRenderStyle:N3D_ShadedWireFrame];
  249.         [[me delegate] cameraParametersWereUpdated:me];
  250.         return TCL_OK;
  251.      }
  252.      if (!strcmp(argv[1], "FacetedSolids"))
  253.      {  [me setRenderStyle:N3D_FacetedSolids];
  254.         [[me delegate] cameraParametersWereUpdated:me];
  255.         return TCL_OK;
  256.      }
  257.      if (!strcmp(argv[1], "SmoothSolids"))
  258.      {  [me setRenderStyle:N3D_SmoothSolids];
  259.         [[me delegate] cameraParametersWereUpdated:me];
  260.         return TCL_OK;
  261.      }
  262.    
  263.      sprintf(errBuf, "ERROR: unknown surface type <%s>\nUSAGE: %s %s", argv[1], argv[0], my_args);
  264.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  265.      return TCL_ERROR;
  266.   }
  267.  
  268.   return TCL_ERROR;
  269. }
  270.  
  271.  
  272.  
  273. static int
  274. cmd_movingRenderStyle(me, interp, argc, argv)
  275. WW3DCamera *me;
  276. Tcl_Interp *interp;
  277. int argc;
  278. char **argv;
  279. {
  280.   char  *my_args = "[PointCloud|WireFrame|ShadedWireFrame|FacetedSolids|SmoothSolids]";
  281.   int   movingRenderStyle;
  282.  
  283.  
  284.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  285.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  286.   if ((argc != 1) && (argc != 2))
  287.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  288.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  289.      return TCL_ERROR;
  290.   }
  291.  
  292.   if (argc == 1)
  293.   {  movingRenderStyle = [me movingRenderStyle];
  294.      if (movingRenderStyle == N3D_PointCloud)
  295.      {  sprintf(interp->result, "PointCloud");
  296.         return TCL_OK;
  297.      }
  298.      if (movingRenderStyle == N3D_WireFrame)
  299.      {  sprintf(interp->result, "WireFrame");
  300.         return TCL_OK;
  301.      }
  302.      if (movingRenderStyle == N3D_ShadedWireFrame)
  303.      {  sprintf(interp->result, "ShadedWireFrame");
  304.         return TCL_OK;
  305.      }
  306.      if (movingRenderStyle == N3D_FacetedSolids)
  307.      {  sprintf(interp->result, "FacetedSolids");
  308.         return TCL_OK;
  309.      }
  310.      if (movingRenderStyle == N3D_SmoothSolids)
  311.      {  sprintf(interp->result, "SmoothSolids");
  312.         return TCL_OK;
  313.      }
  314.      sprintf(interp->result, 
  315.          "Yikes! I have no mapping for movingRenderStyle %d", 
  316.          movingRenderStyle);
  317.      return TCL_ERROR;
  318.   }
  319.   if (argc == 2)
  320.   {  if (!strcmp(argv[1], "PointCloud"))
  321.      {  [me setMovingRenderStyle:N3D_PointCloud];
  322.         [[me delegate] cameraParametersWereUpdated:me];
  323.         return TCL_OK;
  324.      }
  325.      if (!strcmp(argv[1], "WireFrame"))
  326.      {  [me setMovingRenderStyle:N3D_WireFrame];
  327.         [[me delegate] cameraParametersWereUpdated:me];
  328.         return TCL_OK;
  329.      }
  330.      if (!strcmp(argv[1], "ShadedWireFrame"))
  331.      {  [me setMovingRenderStyle:N3D_ShadedWireFrame];
  332.         [[me delegate] cameraParametersWereUpdated:me];
  333.         return TCL_OK;
  334.      }
  335.      if (!strcmp(argv[1], "FacetedSolids"))
  336.      {  [me setMovingRenderStyle:N3D_FacetedSolids];
  337.         [[me delegate] cameraParametersWereUpdated:me];
  338.         return TCL_OK;
  339.      }
  340.      if (!strcmp(argv[1], "SmoothSolids"))
  341.      {  [me setMovingRenderStyle:N3D_SmoothSolids];
  342.         [[me delegate] cameraParametersWereUpdated:me];
  343.         return TCL_OK;
  344.      }
  345.    
  346.      sprintf(errBuf, "ERROR: unknown surface type <%s>\nUSAGE: %s %s", argv[1], argv[0], my_args);
  347.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  348.      return TCL_ERROR;
  349.   }
  350.  
  351.   return TCL_ERROR;
  352. }
  353.  
  354.  
  355.  
  356. static int
  357. cmd_tesselation(me, interp, argc, argv)
  358. WW3DCamera *me;
  359. Tcl_Interp *interp;
  360. int argc;
  361. char **argv;
  362. {
  363.   char  *my_args = "[tesselation]";
  364.  
  365.  
  366.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  367.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  368.   if ((argc != 1) && (argc != 2))
  369.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  370.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  371.      return TCL_ERROR;
  372.   }
  373.  
  374.   if (argc == 1)
  375.   {  sprintf(interp->result, "%f", [me tesselation]);
  376.      return TCL_OK;
  377.   }
  378.   if (argc == 2)
  379.   {  [me setTesselation:(float)atof(argv[1])];
  380.      sprintf(interp->result, "%f", [me tesselation]);
  381.      return TCL_OK;
  382.   }
  383.   return TCL_ERROR;
  384. }
  385.  
  386. static int
  387. cmd_lowRezTesselation(me, interp, argc, argv)
  388. WW3DCamera *me;
  389. Tcl_Interp *interp;
  390. int argc;
  391. char **argv;
  392. {
  393.   char  *my_args = "[lowRezTesselation]";
  394.  
  395.  
  396.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  397.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  398.   if ((argc != 1) && (argc != 2))
  399.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  400.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  401.      return TCL_ERROR;
  402.   }
  403.  
  404.   if (argc == 1)
  405.   {  sprintf(interp->result, "%f", [me lowRezTesselation]);
  406.      return TCL_OK;
  407.   }
  408.   if (argc == 2)
  409.   {  [me setLowRezTesselation:(float)atof(argv[1])];
  410.      sprintf(interp->result, "%f", [me lowRezTesselation]);
  411.      return TCL_OK;
  412.   }
  413.   return TCL_ERROR;
  414. }
  415.  
  416. static int
  417. cmd_fieldOfView(me, interp, argc, argv)
  418. WW3DCamera *me;
  419. Tcl_Interp *interp;
  420. int argc;
  421. char **argv;
  422. {
  423.   char  *my_args = "[fov]";
  424.  
  425.  
  426.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  427.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  428.   if ((argc != 1) && (argc != 2))
  429.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  430.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  431.      return TCL_ERROR;
  432.   }
  433.  
  434.   if (argc == 1)
  435.   {  sprintf(interp->result, "%f", [me fieldOfView]);
  436.      return TCL_OK;
  437.   }
  438.   if (argc == 2)
  439.   {  [me setFieldOfViewByAngle:(float)atof(argv[1])];
  440.      sprintf(interp->result, "%f", [me fieldOfView]);
  441.      return TCL_OK;
  442.   }
  443.   return TCL_ERROR;
  444. }
  445.  
  446. static int
  447. cmd_setEyeAtTowardRoll(me, interp, argc, argv)
  448. WW3DCamera *me;
  449. Tcl_Interp *interp;
  450. int argc;
  451. char **argv;
  452. {
  453.   char     *my_args = "fromPoint toPoint aRollAngle";
  454.   int       num_args = 4, argc2;
  455.   RtPoint  fromPoint, toPoint;
  456.   float    aRollAngle;
  457.   char     **argv2;
  458.  
  459.  
  460.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  461.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  462.   if (argc != num_args)
  463.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  464.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  465.      return TCL_ERROR;
  466.   }
  467.  
  468.   Tcl_SplitList(interp, argv[1], &argc2, &argv2); // fromPoint
  469.   if (argc2 != 3)
  470.   {  sprintf(errBuf, "USAGE: %s %s (points should have 3 components)", argv[0], my_args);
  471.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  472.      if (argv2) { free(argv2); }
  473.      return TCL_ERROR;
  474.   }
  475.   N3D_XComp(fromPoint) = (float)atof(argv2[0]);
  476.   N3D_YComp(fromPoint) = (float)atof(argv2[1]);
  477.   N3D_ZComp(fromPoint) = (float)atof(argv2[2]);
  478.   free(argv2);
  479.  
  480.   Tcl_SplitList(interp, argv[2], &argc2, &argv2); // fromPoint
  481.   if (argc2 != 3)
  482.   {  sprintf(errBuf, "USAGE: %s %s (points should have 3 components)", argv[0], my_args);
  483.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  484.      if (argv2) { free(argv2); }
  485.      return TCL_ERROR;
  486.   }
  487.   N3D_XComp(toPoint) = (float)atof(argv2[0]);
  488.   N3D_YComp(toPoint) = (float)atof(argv2[1]);
  489.   N3D_ZComp(toPoint) = (float)atof(argv2[2]);
  490.   free(argv2);
  491.  
  492.   aRollAngle = (float)atof(argv[3]);
  493.  
  494.   [me setEyeAt:fromPoint toward:toPoint roll:aRollAngle];
  495.  
  496.   return TCL_OK;
  497. }
  498.  
  499. static int
  500. cmd_moveEyeBy(me, interp, argc, argv)
  501. WW3DCamera *me;
  502. Tcl_Interp *interp;
  503. int argc;
  504. char **argv;
  505. {
  506.   char  *my_args = "sDistance tDistance uDistance";
  507.   int    num_args = 4;
  508.  
  509.  
  510.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  511.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  512.   if (argc != num_args)
  513.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  514.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  515.      return TCL_ERROR;
  516.   }
  517.  
  518.   [me moveEyeBy:(float)atof(argv[1]) :(float)atof(argv[2]) :(float)atof(argv[3])]; 
  519.   [[me delegate] cameraParametersWereUpdated:me];
  520.   return TCL_OK;
  521. }
  522.  
  523. static int
  524. cmd_getEyePoint(me, interp, argc, argv)
  525. WW3DCamera *me;
  526. Tcl_Interp *interp;
  527. int argc;
  528. char **argv;
  529. {
  530.   char     *my_args = "";
  531.   int       num_args = 1;
  532.   RtPoint  eyePoint, viewPoint;
  533.   float    aRollAngle;
  534.  
  535.  
  536.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  537.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  538.   if (argc != num_args)
  539.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  540.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  541.      return TCL_ERROR;
  542.   }
  543.  
  544.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  545.   sprintf(interp->result, 
  546.       "%f %f %f", 
  547.       N3D_XComp(eyePoint), N3D_YComp(eyePoint), N3D_ZComp(eyePoint));
  548.   return TCL_OK;
  549. }
  550.  
  551. static int
  552. cmd_getViewPoint(me, interp, argc, argv)
  553. WW3DCamera *me;
  554. Tcl_Interp *interp;
  555. int argc;
  556. char **argv;
  557. {
  558.   char     *my_args = "";
  559.   int       num_args = 1;
  560.   RtPoint  eyePoint, viewPoint;
  561.   float    aRollAngle;
  562.  
  563.  
  564.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  565.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  566.   if (argc != num_args)
  567.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  568.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  569.      return TCL_ERROR;
  570.   }
  571.  
  572.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  573.   sprintf(interp->result, 
  574.       "%f %f %f", 
  575.       N3D_XComp(viewPoint), N3D_YComp(viewPoint), N3D_ZComp(viewPoint));
  576.   return TCL_OK;
  577. }
  578.  
  579. static int
  580. cmd_getRollAngle(me, interp, argc, argv)
  581. WW3DCamera *me;
  582. Tcl_Interp *interp;
  583. int argc;
  584. char **argv;
  585. {
  586.   char     *my_args = "";
  587.   int       num_args = 1;
  588.   RtPoint  eyePoint, viewPoint;
  589.   float    aRollAngle;
  590.  
  591.  
  592.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  593.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  594.   if (argc != num_args)
  595.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  596.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  597.      return TCL_ERROR;
  598.   }
  599.  
  600.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  601.   sprintf(interp->result, "%f", aRollAngle);
  602.   return TCL_OK;
  603. }
  604.  
  605. static int
  606. cmd_getEyeAtTowardRoll(me, interp, argc, argv)
  607. WW3DCamera *me;
  608. Tcl_Interp *interp;
  609. int argc;
  610. char **argv;
  611. {
  612.   char     *my_args = "";
  613.   int       num_args = 1;
  614.   RtPoint  eyePoint, viewPoint;
  615.   float    aRollAngle;
  616.  
  617.  
  618.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  619.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  620.   if (argc != num_args)
  621.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  622.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  623.      return TCL_ERROR;
  624.   }
  625.  
  626.   [me getEyeAt:&eyePoint toward:&viewPoint roll:&aRollAngle];
  627.   sprintf(interp->result, 
  628.       "{%f %f %f} {%f %f %f} %f", 
  629.       N3D_XComp(eyePoint), N3D_YComp(eyePoint), N3D_ZComp(eyePoint),
  630.       N3D_XComp(viewPoint), N3D_YComp(viewPoint), N3D_ZComp(viewPoint),
  631.       aRollAngle);
  632.   return TCL_OK;
  633. }
  634.  
  635. static int
  636. cmd_setSurfaceTypeForAll(me, interp, argc, argv)
  637. WW3DCamera *me;
  638. Tcl_Interp *interp;
  639. int argc;
  640. char **argv;
  641. {
  642.   char  *my_args = "PointCloud|WireFrame|ShadedWireFrame|FacetedSolids|SmoothSolids";
  643.   int    num_args = 2;
  644.  
  645.  
  646.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  647.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  648.   if (argc != num_args)
  649.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  650.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  651.      return TCL_ERROR;
  652.   }
  653.  
  654.   if (!strcmp(argv[1], "PointCloud"))
  655.   {  [me setSurfaceTypeForAll:N3D_PointCloud chooseHider:YES];
  656.      [[me delegate] cameraParametersWereUpdated:me];
  657.      return TCL_OK;
  658.   }
  659.   if (!strcmp(argv[1], "WireFrame"))
  660.   {  [me setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES];
  661.      [[me delegate] cameraParametersWereUpdated:me];
  662.      return TCL_OK;
  663.   }
  664.   if (!strcmp(argv[1], "ShadedWireFrame"))
  665.   {  [me setSurfaceTypeForAll:N3D_ShadedWireFrame chooseHider:YES];
  666.      [[me delegate] cameraParametersWereUpdated:me];
  667.      return TCL_OK;
  668.   }
  669.   if (!strcmp(argv[1], "FacetedSolids"))
  670.   {  [me setSurfaceTypeForAll:N3D_FacetedSolids chooseHider:YES];
  671.      [[me delegate] cameraParametersWereUpdated:me];
  672.      return TCL_OK;
  673.   }
  674.   if (!strcmp(argv[1], "SmoothSolids"))
  675.   {  [me setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  676.      [[me delegate] cameraParametersWereUpdated:me];
  677.      return TCL_OK;
  678.   }
  679.  
  680.   sprintf(errBuf, "ERROR: unknown surface type <%s>\nUSAGE: %s %s", argv[1], argv[0], my_args);
  681.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  682.   return TCL_ERROR;
  683. }
  684.  
  685.  
  686. static int
  687. cmd_removeDefaultLights(me, interp, argc, argv)
  688. WW3DCamera *me;
  689. Tcl_Interp *interp;
  690. int argc;
  691. char **argv;
  692. {
  693.   char  *my_args = "";
  694.   int    num_args = 1;
  695.  
  696.  
  697.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  698.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  699.   if (argc != num_args)
  700.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  701.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  702.      return TCL_ERROR;
  703.   }
  704.  
  705.   [me removeDefaultLights];
  706.   [[me delegate] cameraParametersWereUpdated:me];
  707.  
  708.   return TCL_OK;
  709. }
  710.  
  711. static int
  712. cmd_restoreDefaultLights(me, interp, argc, argv)
  713. WW3DCamera *me;
  714. Tcl_Interp *interp;
  715. int argc;
  716. char **argv;
  717. {
  718.   char  *my_args = "";
  719.   int    num_args = 1;
  720.  
  721.  
  722.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  723.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  724.   if (argc != num_args)
  725.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  726.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  727.      return TCL_ERROR;
  728.   }
  729.  
  730.   [me restoreDefaultLights];
  731.   [[me delegate] cameraParametersWereUpdated:me];
  732.  
  733.   return TCL_OK;
  734. }
  735.  
  736. static int
  737. cmd_lightList(me, interp, argc, argv)
  738. WW3DCamera *me;
  739. Tcl_Interp *interp;
  740. int argc;
  741. char **argv;
  742. {
  743.   char          *my_args = "";
  744.   int            num_args = 1, i;
  745.   id            theLightList;
  746.   N3DLight      *light;
  747.   N3DLightType  lightType;
  748.   char          aBuf[MAXPATHLEN];
  749.   RtPoint       from, to;
  750.   RtFloat       coneAngle, coneDelta, beamDistribution;
  751.   NXColor       color;
  752.  
  753.  
  754.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  755.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  756.   if (argc != num_args)
  757.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  758.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  759.      return TCL_ERROR;
  760.   }
  761.   theLightList = [me lightList];
  762.   
  763.   Tcl_AppendResult(interp, "{", (char *)NULL);
  764.   for (i = 0; i < [theLightList count]; i++)
  765.   {  light = [theLightList objectAt:i];
  766.      Tcl_AppendResult(interp, "{", (char *)NULL);
  767.  
  768.      sprintf(aBuf, "name %s", [light shapeName]);
  769.      Tcl_AppendElement(interp, aBuf);
  770.  
  771.      lightType = [light type];
  772.      switch (lightType)  
  773.      {  case N3D_AmbientLight:  Tcl_AppendElement(interp, "type ambient");
  774.                             break;
  775.         case N3D_PointLight:    Tcl_AppendElement(interp, "type point");
  776.                             break;
  777.         case N3D_DistantLight:  Tcl_AppendElement(interp, "type distant");
  778.                             break;
  779.         case N3D_SpotLight:     Tcl_AppendElement(interp, "type spot");
  780.                             break;
  781.         default:                Tcl_AppendElement(interp, "type unknown");
  782.                             break;
  783.      }
  784.  
  785.      [light getFrom:&from to:&to];
  786.      sprintf(aBuf, "from %f %f %f", from[0], from[1], from[2]);
  787.      Tcl_AppendElement(interp, aBuf);
  788.      sprintf(aBuf, "to %f %f %f", to[0], to[1], to[2]);
  789.      Tcl_AppendElement(interp, aBuf);
  790.  
  791.      sprintf(aBuf, "intensity %f", [light intensity]);
  792.      Tcl_AppendElement(interp, aBuf);
  793.  
  794.      [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  795.      sprintf(aBuf, "coneAngle %f", coneAngle);
  796.      Tcl_AppendElement(interp, aBuf);
  797.      sprintf(aBuf, "coneDelta %f", coneDelta);
  798.      Tcl_AppendElement(interp, aBuf);
  799.      sprintf(aBuf, "beamDistribution %f", beamDistribution);
  800.      Tcl_AppendElement(interp, aBuf);
  801.  
  802.      color = [light color];
  803.      sprintf(aBuf, "color %f %f %f", 
  804.          NXRedComponent(color), NXGreenComponent(color), NXBlueComponent(color));
  805.      Tcl_AppendElement(interp, aBuf);
  806.  
  807.      sprintf(aBuf, "isGlobal %d", (int)[light isGlobal]);
  808.      Tcl_AppendElement(interp, aBuf);
  809.  
  810.      Tcl_AppendResult(interp, "}", (char *)NULL);
  811.   }
  812.   Tcl_AppendResult(interp, "}", (char *)NULL);
  813.   return TCL_OK;
  814. }
  815.  
  816.  
  817. static int
  818. cmd_otherLightList(me, interp, argc, argv)
  819. WW3DCamera *me;
  820. Tcl_Interp *interp;
  821. int argc;
  822. char **argv;
  823. {
  824.   char          *my_args = "";
  825.   int            num_args = 1, i;
  826.   id            theLightList;
  827.   N3DLight      *light;
  828.   N3DLightType  lightType;
  829.   char          aBuf[MAXPATHLEN];
  830.   RtPoint       from, to;
  831.   RtFloat       coneAngle, coneDelta, beamDistribution;
  832.   NXColor       color;
  833.  
  834.  
  835.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  836.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  837.   if (argc != num_args)
  838.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  839.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  840.      return TCL_ERROR;
  841.   }
  842.   theLightList = [me otherLightList];
  843.   
  844.   Tcl_AppendResult(interp, "{", (char *)NULL);
  845.   for (i = 0; i < [theLightList count]; i++)
  846.   {  light = [theLightList objectAt:i];
  847.      Tcl_AppendResult(interp, "{", (char *)NULL);
  848.  
  849.      sprintf(aBuf, "name %s", [light shapeName]);
  850.      Tcl_AppendElement(interp, aBuf);
  851.  
  852.      lightType = [light type];
  853.      switch (lightType)  
  854.      {  case N3D_AmbientLight:  Tcl_AppendElement(interp, "type ambient");
  855.                             break;
  856.         case N3D_PointLight:    Tcl_AppendElement(interp, "type point");
  857.                             break;
  858.         case N3D_DistantLight:  Tcl_AppendElement(interp, "type distant");
  859.                             break;
  860.         case N3D_SpotLight:     Tcl_AppendElement(interp, "type spot");
  861.                             break;
  862.         default:                Tcl_AppendElement(interp, "type unknown");
  863.                             break;
  864.      }
  865.  
  866.      [light getFrom:&from to:&to];
  867.      sprintf(aBuf, "from %f %f %f", from[0], from[1], from[2]);
  868.      Tcl_AppendElement(interp, aBuf);
  869.      sprintf(aBuf, "to %f %f %f", to[0], to[1], to[2]);
  870.      Tcl_AppendElement(interp, aBuf);
  871.  
  872.      sprintf(aBuf, "intensity %f", [light intensity]);
  873.      Tcl_AppendElement(interp, aBuf);
  874.  
  875.      [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  876.      sprintf(aBuf, "coneAngle %f", coneAngle);
  877.      Tcl_AppendElement(interp, aBuf);
  878.      sprintf(aBuf, "coneDelta %f", coneDelta);
  879.      Tcl_AppendElement(interp, aBuf);
  880.      sprintf(aBuf, "beamDistribution %f", beamDistribution);
  881.      Tcl_AppendElement(interp, aBuf);
  882.  
  883.      color = [light color];
  884.      sprintf(aBuf, "color %f %f %f", 
  885.          NXRedComponent(color), NXGreenComponent(color), NXBlueComponent(color));
  886.      Tcl_AppendElement(interp, aBuf);
  887.  
  888.      sprintf(aBuf, "isGlobal %d", (int)[light isGlobal]);
  889.      Tcl_AppendElement(interp, aBuf);
  890.  
  891.      Tcl_AppendResult(interp, "}", (char *)NULL);
  892.   }
  893.   Tcl_AppendResult(interp, "}", (char *)NULL);
  894.   return TCL_OK;
  895. }
  896.  
  897.  
  898. static int
  899. cmd_addAmbientLight(me, interp, argc, argv)
  900. WW3DCamera *me;
  901. Tcl_Interp *interp;
  902. int argc;
  903. char **argv;
  904. {
  905.   char       *my_args = "name intensity [pathToParent]";
  906.   int         num_args = 3;
  907.   WW3DLight  *light;
  908.  
  909.  
  910.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  911.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  912.   if ((argc != num_args) && (argc != (num_args+1)))
  913.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  914.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  915.      return TCL_ERROR;
  916.   }
  917.   light = [[[WW3DLight alloc] init] makeAmbientWithIntensity:(RtFloat)atof(argv[2])];
  918.   [light setShapeName:argv[1]];
  919.   if (argc == (num_args + 1)) // local, visible light
  920.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  921.      {  sprintf(errBuf, "unable to add local ambient light %s as a child of shape %s", argv[1], argv[num_args]); 
  922.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  923.         return TCL_ERROR;
  924.      }
  925.   }
  926.   else  // regular global light
  927.   {  [me addLight:light];
  928.   }
  929.   return TCL_OK;
  930. }
  931.  
  932.  
  933. static int
  934. cmd_addPointLight(me, interp, argc, argv)
  935. WW3DCamera *me;
  936. Tcl_Interp *interp;
  937. int argc;
  938. char **argv;
  939. {
  940.   char       *my_args = "name fromX fromY fromZ intensity [pathToParent]";
  941.   int         num_args = 6;
  942.   RtPoint    from;
  943.   WW3DLight  *light;
  944.  
  945.  
  946.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  947.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  948.   if ((argc != num_args) && (argc != (num_args+1)))
  949.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  950.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  951.      return TCL_ERROR;
  952.   }
  953.   from[0] = (RtFloat)atof(argv[2]);
  954.   from[1] = (RtFloat)atof(argv[3]);
  955.   from[2] = (RtFloat)atof(argv[4]);
  956.   light = [[[WW3DLight alloc] init] makePointFrom:from intensity:(RtFloat)atof(argv[4])];
  957.   [light setShapeName:argv[1]];
  958.   if (argc == (num_args + 1)) // local, visible light
  959.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  960.      {  sprintf(errBuf, "unable to add local point light %s as a child of shape %s", argv[1], argv[num_args]); 
  961.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  962.         return TCL_ERROR;
  963.      }
  964.   }
  965.   else  // regular global light
  966.   {  [me addLight:light];
  967.   }
  968.  
  969.   return TCL_OK;
  970. }
  971.  
  972.  
  973. static int
  974. cmd_addDistantLight(me, interp, argc, argv)
  975. WW3DCamera *me;
  976. Tcl_Interp *interp;
  977. int argc;
  978. char **argv;
  979. {
  980.   char       *my_args = "name fromX fromY fromZ toX toY toZ intensity [pathToParent]";
  981.   int         num_args = 9;
  982.   RtPoint    from, to;
  983.   WW3DLight  *light;
  984.  
  985.  
  986.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  987.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  988.   if ((argc != num_args) && (argc != (num_args+1)))
  989.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  990.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  991.      return TCL_ERROR;
  992.   }
  993.   from[0] = (RtFloat)atof(argv[2]);
  994.   from[1] = (RtFloat)atof(argv[3]);
  995.   from[2] = (RtFloat)atof(argv[4]);
  996.   to[0] = (RtFloat)atof(argv[5]);
  997.   to[1] = (RtFloat)atof(argv[6]);
  998.   to[2] = (RtFloat)atof(argv[7]);
  999.   light = [[[WW3DLight alloc] init] makeDistantFrom:from to:to intensity:(RtFloat)atof(argv[8])];
  1000.   [light setShapeName:argv[1]];
  1001.   if (argc == (num_args + 1)) // local, visible light
  1002.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  1003.      {  sprintf(errBuf, "unable to add local distant light %s as a child of shape %s", argv[1], argv[num_args]); 
  1004.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1005.         return TCL_ERROR;
  1006.      }
  1007.   }
  1008.   else  // regular global light
  1009.   {  [me addLight:light];
  1010.   }
  1011.  
  1012.   return TCL_OK;
  1013. }
  1014.  
  1015.  
  1016. static int
  1017. cmd_addSpotLight(me, interp, argc, argv)
  1018. WW3DCamera *me;
  1019. Tcl_Interp *interp;
  1020. int argc;
  1021. char **argv;
  1022. {
  1023.   char       *my_args = "name fromX fromY fromZ toX toY toZ coneAngle coneDelta beamDistribution intensity [pathToParent]";
  1024.   int         num_args = 12;
  1025.   RtPoint    from, to;
  1026.   WW3DLight  *light;
  1027.  
  1028.  
  1029.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1030.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1031.   if ((argc != num_args) && (argc != (num_args+1)))
  1032.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1033.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1034.      return TCL_ERROR;
  1035.   }
  1036.   from[0] = (RtFloat)atof(argv[2]);
  1037.   from[1] = (RtFloat)atof(argv[3]);
  1038.   from[2] = (RtFloat)atof(argv[4]);
  1039.   to[0] = (RtFloat)atof(argv[5]);
  1040.   to[1] = (RtFloat)atof(argv[6]);
  1041.   to[2] = (RtFloat)atof(argv[7]);
  1042.   light = [[[WW3DLight alloc] init] makeSpotFrom:from to:to 
  1043.                                          coneAngle:(RtFloat)atof(argv[8]) 
  1044.                                         coneDelta:(RtFloat)atof(argv[9]) 
  1045.                                         beamDistribution:(RtFloat)atof(argv[10]) 
  1046.                                         intensity:(RtFloat)atof(argv[11])];
  1047.   [light setShapeName:argv[1]];
  1048.   if (argc == (num_args + 1)) // local, visible light
  1049.   {  if (![me addLocalLight:light usingPath:argv[num_args]])
  1050.      {  sprintf(errBuf, "unable to add local point light %s as a child of shape %s", argv[1], argv[num_args]); 
  1051.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1052.         return TCL_ERROR;
  1053.      }
  1054.   }
  1055.   else  // regular global light
  1056.   {  [me addLight:light];
  1057.   }
  1058.  
  1059.   return TCL_OK;
  1060. }
  1061.  
  1062.  
  1063. static int
  1064. cmd_setLightIntensity(me, interp, argc, argv)
  1065. WW3DCamera *me;
  1066. Tcl_Interp *interp;
  1067. int argc;
  1068. char **argv;
  1069. {
  1070.   char       *my_args = "name intensity";
  1071.   int         num_args = 3, i;
  1072.   WW3DLight  *light;
  1073.   id         lightList = [me lightList];
  1074.   id         otherLightList = [me otherLightList];
  1075.  
  1076.  
  1077.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1078.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1079.   if (argc != num_args)
  1080.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1081.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1082.      return TCL_ERROR;
  1083.   }
  1084.   
  1085.   for (i = 0; i < [lightList count]; i++)
  1086.   {  light = [lightList objectAt:i];
  1087.      if (!strcmp(argv[1], [light shapeName]))
  1088.      {  [light setIntensity:(RtFloat)atof(argv[2])];
  1089.         return TCL_OK;
  1090.      }
  1091.   }
  1092.  
  1093.   for (i = 0; i < [otherLightList count]; i++)
  1094.   {  light = [otherLightList objectAt:i];
  1095.      if (!strcmp(argv[1], [light shapeName]))
  1096.      {  [light setIntensity:(RtFloat)atof(argv[2])];
  1097.         return TCL_OK;
  1098.      }
  1099.   }
  1100.  
  1101.   sprintf(errBuf, "no light named %s - unable to set intensity...", argv[1]);
  1102.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1103.   return TCL_ERROR;
  1104. }
  1105.  
  1106.  
  1107. static int
  1108. cmd_setLightType(me, interp, argc, argv)
  1109. WW3DCamera *me;
  1110. Tcl_Interp *interp;
  1111. int argc;
  1112. char **argv;
  1113. {
  1114.   char          *my_args = "name type";
  1115.   int            num_args = 3, i;
  1116.   WW3DLight     *light;
  1117.   id            lightList = [me lightList];
  1118.   id         otherLightList = [me otherLightList];
  1119.   N3DLightType  lightType = N3D_AmbientLight;
  1120.   BOOL          validLightType = NO;
  1121.  
  1122.  
  1123.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1124.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1125.   if (argc != num_args)
  1126.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1127.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1128.      return TCL_ERROR;
  1129.   }
  1130.  
  1131.   if (!strcmp(argv[2], "ambient"))
  1132.   {  lightType = N3D_AmbientLight;
  1133.      validLightType = YES;
  1134.   }
  1135.   if (!strcmp(argv[2], "point"))
  1136.   {  lightType = N3D_PointLight;
  1137.      validLightType = YES;
  1138.   }
  1139.   if (!strcmp(argv[2], "distant"))
  1140.   {  lightType = N3D_DistantLight;
  1141.      validLightType = YES;
  1142.   }
  1143.   if (!strcmp(argv[2], "spot"))
  1144.   {  lightType = N3D_SpotLight;
  1145.      validLightType = YES;
  1146.   }
  1147.   if (!validLightType)
  1148.   {  sprintf(errBuf, "%s is not a valid light type (ambient|point|distant|spot)", argv[2]);
  1149.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1150.      return TCL_ERROR;
  1151.   }
  1152.  
  1153.   for (i = 0; i < [lightList count]; i++)
  1154.   {  light = [lightList objectAt:i];
  1155.      if (!strcmp(argv[1], [light shapeName]))
  1156.      {  [light setType:lightType];
  1157.         return TCL_OK;
  1158.      }
  1159.   }
  1160.  
  1161.   for (i = 0; i < [otherLightList count]; i++)
  1162.   {  light = [otherLightList objectAt:i];
  1163.      if (!strcmp(argv[1], [light shapeName]))
  1164.      {  [light setType:lightType];
  1165.         return TCL_OK;
  1166.      }
  1167.   }
  1168.  
  1169.   sprintf(errBuf, "no light named %s - unable to set type...", argv[1]);
  1170.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1171.   return TCL_ERROR;
  1172. }
  1173.  
  1174.  
  1175. static int
  1176. cmd_setLightFrom(me, interp, argc, argv)
  1177. WW3DCamera *me;
  1178. Tcl_Interp *interp;
  1179. int argc;
  1180. char **argv;
  1181. {
  1182.   char       *my_args = "name fromX fromY fromZ";
  1183.   int         num_args = 5, i;
  1184.   RtPoint    from;
  1185.   WW3DLight  *light;
  1186.   id         lightList = [me lightList];
  1187.   id         otherLightList = [me otherLightList];
  1188.  
  1189.  
  1190.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1191.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1192.   if (argc != num_args)
  1193.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1194.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1195.      return TCL_ERROR;
  1196.   }
  1197.   from[0] = (RtFloat)atof(argv[2]);
  1198.   from[1] = (RtFloat)atof(argv[3]);
  1199.   from[2] = (RtFloat)atof(argv[4]);
  1200.  
  1201.   for (i = 0; i < [lightList count]; i++)
  1202.   {  light = [lightList objectAt:i];
  1203.      if (!strcmp(argv[1], [light shapeName]))
  1204.      {  [light setFrom:from];
  1205.         return TCL_OK;
  1206.      }
  1207.   }
  1208.   for (i = 0; i < [otherLightList count]; i++)
  1209.   {  light = [otherLightList objectAt:i];
  1210.      if (!strcmp(argv[1], [light shapeName]))
  1211.      {  [light setFrom:from];
  1212.         return TCL_OK;
  1213.      }
  1214.   }
  1215.  
  1216.   sprintf(errBuf, "no light named %s - unable to set from point...", argv[1]);
  1217.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1218.   return TCL_ERROR;
  1219. }
  1220.  
  1221.  
  1222. static int
  1223. cmd_setLightTo(me, interp, argc, argv)
  1224. WW3DCamera *me;
  1225. Tcl_Interp *interp;
  1226. int argc;
  1227. char **argv;
  1228. {
  1229.   char       *my_args = "name toX toY toZ";
  1230.   int         num_args = 5, i;
  1231.   RtPoint    from, to;
  1232.   WW3DLight  *light;
  1233.   id         lightList = [me lightList];
  1234.   id         otherLightList = [me otherLightList];
  1235.  
  1236.  
  1237.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1238.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1239.   if (argc != num_args)
  1240.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1241.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1242.      return TCL_ERROR;
  1243.   }
  1244.  
  1245.   for (i = 0; i < [lightList count]; i++)
  1246.   {  light = [lightList objectAt:i];
  1247.      if (!strcmp(argv[1], [light shapeName]))
  1248.      {  [light getFrom:&from to:&to];
  1249.         to[0] = (RtFloat)atof(argv[2]);
  1250.         to[1] = (RtFloat)atof(argv[3]);
  1251.         to[2] = (RtFloat)atof(argv[4]);
  1252.         [light setFrom:from to:to];
  1253.         return TCL_OK;
  1254.      }
  1255.   }
  1256.  
  1257.   for (i = 0; i < [otherLightList count]; i++)
  1258.   {  light = [otherLightList objectAt:i];
  1259.      if (!strcmp(argv[1], [light shapeName]))
  1260.      {  [light getFrom:&from to:&to];
  1261.         to[0] = (RtFloat)atof(argv[2]);
  1262.         to[1] = (RtFloat)atof(argv[3]);
  1263.         to[2] = (RtFloat)atof(argv[4]);
  1264.         [light setFrom:from to:to];
  1265.         return TCL_OK;
  1266.      }
  1267.   }
  1268.  
  1269.   sprintf(errBuf, "no light named %s - unable to set to point...", argv[1]);
  1270.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1271.   return TCL_ERROR;
  1272. }
  1273.  
  1274.  
  1275. static int
  1276. cmd_setLightColor(me, interp, argc, argv)
  1277. WW3DCamera *me;
  1278. Tcl_Interp *interp;
  1279. int argc;
  1280. char **argv;
  1281. {
  1282.   char       *my_args = "name r g b";
  1283.   int         num_args = 5, i;
  1284.   NXColor    color;
  1285.   WW3DLight  *light;
  1286.   id         lightList = [me lightList];
  1287.   id         otherLightList = [me otherLightList];
  1288.  
  1289.  
  1290.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1291.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1292.   if (argc != num_args)
  1293.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1294.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1295.      return TCL_ERROR;
  1296.   }
  1297.   color = NXConvertRGBToColor((float)atof(argv[2]), (float)atof(argv[3]), (float)atof(argv[4]));
  1298.   for (i = 0; i < [lightList count]; i++)
  1299.   {  light = [lightList objectAt:i];
  1300.      if (!strcmp(argv[1], [light shapeName]))
  1301.      {  [light setColor:color];
  1302.         return TCL_OK;
  1303.      }
  1304.   }
  1305.  
  1306.   for (i = 0; i < [otherLightList count]; i++)
  1307.   {  light = [otherLightList objectAt:i];
  1308.      if (!strcmp(argv[1], [light shapeName]))
  1309.      {  [light setColor:color];
  1310.         return TCL_OK;
  1311.      }
  1312.   }
  1313.  
  1314.   sprintf(errBuf, "no light named %s - unable to set color...", argv[1]);
  1315.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1316.   return TCL_ERROR;
  1317. }
  1318.  
  1319.  
  1320. static int
  1321. cmd_setLightConeAngleConeDeltaBeamDistribution(me, interp, argc, argv)
  1322. WW3DCamera *me;
  1323. Tcl_Interp *interp;
  1324. int argc;
  1325. char **argv;
  1326. {
  1327.   char       *my_args = "name coneAngle coneDelta beamDistribution";
  1328.   int         num_args = 5, i;
  1329.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1330.   WW3DLight  *light;
  1331.   id         lightList = [me lightList];
  1332.   id         otherLightList = [me otherLightList];
  1333.  
  1334.  
  1335.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1336.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1337.   if (argc != num_args)
  1338.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1339.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1340.      return TCL_ERROR;
  1341.   }
  1342.   
  1343.   for (i = 0; i < [lightList count]; i++)
  1344.   {  light = [lightList objectAt:i];
  1345.      if (!strcmp(argv[1], [light shapeName]))
  1346.      {  coneAngle = (RtFloat)atof(argv[2]);
  1347.         coneDelta = (RtFloat)atof(argv[3]);
  1348.         beamDistribution = (RtFloat)atof(argv[4]);
  1349.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1350.         return TCL_OK;
  1351.      }
  1352.   }
  1353.  
  1354.   for (i = 0; i < [otherLightList count]; i++)
  1355.   {  light = [otherLightList objectAt:i];
  1356.      if (!strcmp(argv[1], [light shapeName]))
  1357.      {  coneAngle = (RtFloat)atof(argv[2]);
  1358.         coneDelta = (RtFloat)atof(argv[3]);
  1359.         beamDistribution = (RtFloat)atof(argv[4]);
  1360.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1361.         return TCL_OK;
  1362.      }
  1363.   }
  1364.  
  1365.   sprintf(errBuf, "no light named %s - unable to set coneAngle, coneDelta, beamDistribution...", argv[1]);
  1366.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1367.   return TCL_ERROR;
  1368. }
  1369.  
  1370.  
  1371. static int
  1372. cmd_setLightConeAngle(me, interp, argc, argv)
  1373. WW3DCamera *me;
  1374. Tcl_Interp *interp;
  1375. int argc;
  1376. char **argv;
  1377. {
  1378.   char       *my_args = "name coneAngle";
  1379.   int         num_args = 3, i;
  1380.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1381.   WW3DLight  *light;
  1382.   id         lightList = [me lightList];
  1383.   id         otherLightList = [me otherLightList];
  1384.  
  1385.  
  1386.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1387.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1388.   if (argc != num_args)
  1389.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1390.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1391.      return TCL_ERROR;
  1392.   }
  1393.   
  1394.   for (i = 0; i < [lightList count]; i++)
  1395.   {  light = [lightList objectAt:i];
  1396.      if (!strcmp(argv[1], [light shapeName]))
  1397.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1398.         coneAngle = (RtFloat)atof(argv[2]);
  1399.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1400.         return TCL_OK;
  1401.      }
  1402.   }
  1403.  
  1404.   for (i = 0; i < [otherLightList count]; i++)
  1405.   {  light = [otherLightList objectAt:i];
  1406.      if (!strcmp(argv[1], [light shapeName]))
  1407.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1408.         coneAngle = (RtFloat)atof(argv[2]);
  1409.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1410.         return TCL_OK;
  1411.      }
  1412.   }
  1413.  
  1414.   sprintf(errBuf, "no light named %s - unable to set coneAngle...", argv[1]);
  1415.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1416.   return TCL_ERROR;
  1417. }
  1418.  
  1419.  
  1420. static int
  1421. cmd_setLightConeDelta(me, interp, argc, argv)
  1422. WW3DCamera *me;
  1423. Tcl_Interp *interp;
  1424. int argc;
  1425. char **argv;
  1426. {
  1427.   char       *my_args = "name coneDelta";
  1428.   int         num_args = 3, i;
  1429.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1430.   WW3DLight  *light;
  1431.   id         lightList = [me lightList];
  1432.   id         otherLightList = [me otherLightList];
  1433.  
  1434.  
  1435.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1436.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1437.   if (argc != num_args)
  1438.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1439.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1440.      return TCL_ERROR;
  1441.   }
  1442.   
  1443.   for (i = 0; i < [lightList count]; i++)
  1444.   {  light = [lightList objectAt:i];
  1445.      if (!strcmp(argv[1], [light shapeName]))
  1446.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1447.         coneDelta = (RtFloat)atof(argv[2]);
  1448.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1449.         return TCL_OK;
  1450.      }
  1451.   }
  1452.  
  1453.   for (i = 0; i < [otherLightList count]; i++)
  1454.   {  light = [otherLightList objectAt:i];
  1455.      if (!strcmp(argv[1], [light shapeName]))
  1456.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1457.         coneDelta = (RtFloat)atof(argv[2]);
  1458.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1459.         return TCL_OK;
  1460.      }
  1461.   }
  1462.  
  1463.   sprintf(errBuf, "no light named %s - unable to set coneDelta...", argv[1]);
  1464.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1465.   return TCL_ERROR;
  1466. }
  1467.  
  1468.  
  1469. static int
  1470. cmd_setLightBeamDistribution(me, interp, argc, argv)
  1471. WW3DCamera *me;
  1472. Tcl_Interp *interp;
  1473. int argc;
  1474. char **argv;
  1475. {
  1476.   char       *my_args = "name beamDistribution";
  1477.   int         num_args = 3, i;
  1478.   RtFloat    coneAngle, coneDelta, beamDistribution;
  1479.   WW3DLight  *light;
  1480.   id         lightList = [me lightList];
  1481.   id         otherLightList = [me otherLightList];
  1482.  
  1483.  
  1484.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1485.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1486.   if (argc != num_args)
  1487.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1488.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1489.      return TCL_ERROR;
  1490.   }
  1491.   
  1492.   for (i = 0; i < [lightList count]; i++)
  1493.   {  light = [lightList objectAt:i];
  1494.      if (!strcmp(argv[1], [light shapeName]))
  1495.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1496.         beamDistribution = (RtFloat)atof(argv[2]);
  1497.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1498.         return TCL_OK;
  1499.      }
  1500.   }
  1501.  
  1502.   for (i = 0; i < [otherLightList count]; i++)
  1503.   {  light = [otherLightList objectAt:i];
  1504.      if (!strcmp(argv[1], [light shapeName]))
  1505.      {  [light getConeAngle:&coneAngle coneDelta:&coneDelta beamDistribution:&beamDistribution];
  1506.         beamDistribution = (RtFloat)atof(argv[2]);
  1507.         [light setConeAngle:coneAngle coneDelta:coneDelta beamDistribution:beamDistribution];
  1508.         return TCL_OK;
  1509.      }
  1510.   }
  1511.  
  1512.   sprintf(errBuf, "no light named %s - unable to set beamDistribution...", argv[1]);
  1513.   Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1514.   return TCL_ERROR;
  1515. }
  1516.  
  1517.  
  1518. static int
  1519. cmd_removeLight(me, interp, argc, argv)
  1520. WW3DCamera *me;
  1521. Tcl_Interp *interp;
  1522. int argc;
  1523. char **argv;
  1524. {
  1525.   int            i;
  1526.  
  1527.  
  1528.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1529.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1530.   for (i = 1; i < argc; i++)
  1531.   {  if (![me removeLightNamed:argv[i]])
  1532.      {  sprintf(errBuf, "no light named %s - no further light removal done...", argv[i]);
  1533.         Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1534.         return TCL_ERROR;
  1535.      }
  1536.   }
  1537.  
  1538.   return TCL_OK;
  1539. }
  1540.  
  1541.  
  1542. static int
  1543. cmd_rotateAroundY(me, interp, argc, argv)
  1544. WW3DCamera *me;
  1545. Tcl_Interp *interp;
  1546. int argc;
  1547. char **argv;
  1548. {
  1549.   char       *my_args = "u", **argv2, *str;
  1550.   int         num_args = 2, argc2;
  1551.   RtPoint    originalView;
  1552.   RtPoint    originalEye, newEye;
  1553.   double     u, radius, radiusSq;
  1554.   RtFloat    originalRollAngle;
  1555.  
  1556.  
  1557.   //sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1558.   //[[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1559.  
  1560.   if (argc != num_args)
  1561.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1562.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1563.      return TCL_ERROR;
  1564.   }
  1565.  
  1566.   // u varies from 0 to 1, and describes a perfect circle around the original look at point.
  1567.   // we want to stay at the same Y point, and move around in a circle, such that the radius
  1568.   // of the circle we're describing stays constant.  
  1569.   // we just want to set a new eye point and then reset the viewpoint to be the same as it had been.
  1570.   u = (float)atof(argv[1]);
  1571.   
  1572.   // need to grab "startCam(eyePoint)", which is a list
  1573.   str = [[me tclInterp] getVar2:"startCam" :"eyePoint"];
  1574.   if (!str)
  1575.   {  sprintf(errBuf, "startCam(viewPoint) is no defined - unable to interpolate");
  1576.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1577.      return TCL_ERROR;
  1578.   }
  1579.   Tcl_SplitList(interp, str, &argc2, &argv2);
  1580.   if (argc2 != 3)
  1581.   {  sprintf(errBuf, "startCam(eyePoint) is supposed to have 3 elements, not %d", argc2);
  1582.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1583.      return TCL_ERROR;
  1584.   }
  1585.   N3D_XComp(originalEye) = (float)atof(argv2[0]);
  1586.   N3D_YComp(originalEye) = (float)atof(argv2[1]);
  1587.   N3D_ZComp(originalEye) = (float)atof(argv2[2]);
  1588.  
  1589.   // need to grab "startCam(viewPoint)", which is a list
  1590.   str = [[me tclInterp] getVar2:"startCam" :"viewPoint"];
  1591.   if (!str)
  1592.   {  sprintf(errBuf, "startCam(viewPoint) is no defined - unable to interpolate");
  1593.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1594.      return TCL_ERROR;
  1595.   }
  1596.   Tcl_SplitList(interp, str, &argc2, &argv2);
  1597.   if (argc2 != 3)
  1598.   {  sprintf(errBuf, "startCam(viewPoint) is supposed to have 3 elements, not %d", argc2);
  1599.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1600.      return TCL_ERROR;
  1601.   }
  1602.   N3D_XComp(originalView) = (float)atof(argv2[0]);
  1603.   N3D_YComp(originalView) = (float)atof(argv2[1]);
  1604.   N3D_ZComp(originalView) = (float)atof(argv2[2]);
  1605.  
  1606.   radiusSq =   ((N3D_XComp(originalEye) - N3D_XComp(originalView)) * (N3D_XComp(originalEye) - N3D_XComp(originalView)))
  1607.              + ((N3D_ZComp(originalEye) - N3D_ZComp(originalView)) * (N3D_ZComp(originalEye) - N3D_ZComp(originalView)));
  1608.   radius = sqrt(radiusSq);
  1609.   NXLogError("radius == %f\n", radius);
  1610.   N3D_XComp(newEye) = N3D_XComp(originalView) + ((N3D_XComp(originalEye) - N3D_XComp(originalView)) * cos(2 * PI * u));
  1611.   N3D_YComp(newEye) = N3D_YComp(originalEye);
  1612.   N3D_ZComp(newEye) = N3D_ZComp(originalView) + ((N3D_ZComp(originalEye) - N3D_ZComp(originalView)) * sin(2 * PI * u));
  1613.  
  1614.   // need to grab "startCam(rollAngle)"
  1615.   str = [[me tclInterp] getVar2:"startCam" :"rollAngle"];
  1616.   originalRollAngle = (RtFloat)atof(str);
  1617.  
  1618.   [me setEyeAt:newEye toward:originalView roll:originalRollAngle];
  1619.  
  1620.   return TCL_OK;
  1621. }
  1622.  
  1623. static int
  1624. cmd_noop(me, interp, argc, argv)
  1625. WW3DCamera *me;
  1626. Tcl_Interp *interp;
  1627. int argc;
  1628. char **argv;
  1629. {
  1630.   sprintf(errBuf, "WW3DCamera's interp evaluating %s...", argv[0]);
  1631.   [[me statusText] setStringValue:errBuf]; [[me statusText] display]; NXPing();
  1632.   return TCL_OK;
  1633. }
  1634.  
  1635. #if 0
  1636. static int
  1637. cmd_(me, interp, argc, argv)
  1638. WW3DCamera *me;
  1639. Tcl_Interp *interp;
  1640. int argc;
  1641. char **argv;
  1642. {
  1643.   char  *my_args = "";
  1644.   int    num_args = 1;
  1645.  
  1646.  
  1647.   if (argc != num_args)
  1648.   {  sprintf(errBuf, "USAGE: %s %s", argv[0], my_args);
  1649.      Tcl_AppendResult(interp, errBuf, (char *)NULL);
  1650.      return TCL_ERROR;
  1651.   }
  1652.  
  1653.   return TCL_OK;
  1654. }
  1655. #endif
  1656.  
  1657. - initInterp
  1658. {
  1659.   [tclInterp addCommand:"dumpRIBToFile" :cmd_dumpRIBToFile :self];
  1660.   [tclInterp addCommand:"display" :cmd_display :self];
  1661.   [tclInterp addCommand:"renderStyle" :cmd_renderStyle :self];
  1662.   [tclInterp addCommand:"movingRenderStyle" :cmd_movingRenderStyle :self];
  1663.   [tclInterp addCommand:"tesselation" :cmd_tesselation :self];
  1664.   [tclInterp addCommand:"lowRezTesselation" :cmd_lowRezTesselation :self];
  1665.   [tclInterp addCommand:"backgroundColor" :cmd_backgroundColor :self];
  1666.   [tclInterp addCommand:"fieldOfView" :cmd_fieldOfView :self];
  1667.   [tclInterp addCommand:"setEyeAt:toward:roll:" :cmd_setEyeAtTowardRoll :self];
  1668.   [tclInterp addCommand:"setEyeAtTowardRoll" :cmd_setEyeAtTowardRoll :self];
  1669.   [tclInterp addCommand:"moveEyeBy:::" :cmd_moveEyeBy :self];
  1670.   [tclInterp addCommand:"moveEyeBy" :cmd_moveEyeBy :self];
  1671.   [tclInterp addCommand:"setSurfaceTypeForAll" :cmd_setSurfaceTypeForAll :self];
  1672.   [tclInterp addCommand:"getEyePoint" :cmd_getEyePoint :self];
  1673.   [tclInterp addCommand:"getViewPoint" :cmd_getViewPoint :self];
  1674.   [tclInterp addCommand:"getRollAngle" :cmd_getRollAngle :self];
  1675.   [tclInterp addCommand:"getEyeAt:toward:roll:" :cmd_getEyeAtTowardRoll :self];
  1676.   [tclInterp addCommand:"getEyeAtTowardRoll" :cmd_getEyeAtTowardRoll :self];
  1677.   [tclInterp addCommand:"removeDefaultLights" :cmd_removeDefaultLights :self];
  1678.   [tclInterp addCommand:"restoreDefaultLights" :cmd_restoreDefaultLights :self];
  1679.   [tclInterp addCommand:"lightList" :cmd_lightList :self];
  1680.   [tclInterp addCommand:"otherLightList" :cmd_otherLightList :self];
  1681.   [tclInterp addCommand:"localLightList" :cmd_otherLightList :self];
  1682.   [tclInterp addCommand:"addAmbientLight" :cmd_addAmbientLight :self];
  1683.   [tclInterp addCommand:"addPointLight" :cmd_addPointLight :self];
  1684.   [tclInterp addCommand:"addDistantLight" :cmd_addDistantLight :self];
  1685.   [tclInterp addCommand:"addSpotLight" :cmd_addSpotLight :self];
  1686.   [tclInterp addCommand:"setLightIntensity" :cmd_setLightIntensity :self];
  1687.   [tclInterp addCommand:"setLightType" :cmd_setLightType :self];
  1688.   [tclInterp addCommand:"setLightFrom" :cmd_setLightFrom :self];
  1689.   [tclInterp addCommand:"setLightTo" :cmd_setLightTo :self];
  1690.   [tclInterp addCommand:"setLightColor" :cmd_setLightColor :self];
  1691.   [tclInterp addCommand:"setLightConeAngleConeDeltaBeamDistribution" :cmd_setLightConeAngleConeDeltaBeamDistribution :self];
  1692.   [tclInterp addCommand:"setLightConeAngle" :cmd_setLightConeAngle :self];
  1693.   [tclInterp addCommand:"setLightConeDelta" :cmd_setLightConeDelta :self];
  1694.   [tclInterp addCommand:"setLightBeamDistribution" :cmd_setLightBeamDistribution :self];
  1695.   [tclInterp addCommand:"removeLight" :cmd_removeLight :self];
  1696.  
  1697.   [tclInterp addCommand:"rotateAroundY" :cmd_rotateAroundY :self];
  1698.  
  1699.   [tclInterp addCommand:"askModel" :cmd_noop :self];
  1700.   [tclInterp addCommand:"noop" :cmd_noop :self];
  1701.  
  1702.   return self;
  1703. }
  1704.  
  1705. - setupDefaultLights
  1706. {
  1707.    RtPoint lFromP = {0.5,0.5,-0.75};
  1708.    RtPoint lToP = {0, 0, 0};
  1709.  
  1710.    // ambient light
  1711.    ambientLight=[[WW3DLight alloc] init];
  1712.    [ambientLight setShapeName:"ambientLight"];
  1713.    [ambientLight makeAmbientWithIntensity:0.3];
  1714.    [self addLight:ambientLight];
  1715.  
  1716.    // distant light
  1717.    rightLight=[[WW3DLight alloc] init];
  1718.    [rightLight setShapeName:"rightDistantLight"];
  1719.    [rightLight makeDistantFrom:lFromP to:lToP intensity:0.7];
  1720.    [self addLight:rightLight];
  1721.  
  1722.   // point light
  1723.   //N3D_XComp( lFromP ) = -0.5;
  1724.   //N3D_YComp( lFromP ) = -0.5;
  1725.   //leftLight=[[WW3DLight alloc] init];
  1726.   //[leftLight setShapeName:"leftPointLight"];
  1727.   //[leftLight makePointFrom:lFromP intensity:0.7];
  1728.   //[self addLight:leftLight];
  1729.  
  1730.   defaultLightsInUse = YES;
  1731.  
  1732.   return self;
  1733. }
  1734.  
  1735. - restoreDefaultLights
  1736. {
  1737.   if (!defaultLightsInUse)
  1738.   {  [self addLight:ambientLight];
  1739.      [self addLight:rightLight];
  1740.      //[self addLight:leftLight];
  1741.      defaultLightsInUse = YES;
  1742.   }
  1743.   return self;
  1744. }
  1745.  
  1746. - removeDefaultLights
  1747. {
  1748.   if (defaultLightsInUse)
  1749.   {  [self removeLight:ambientLight];
  1750.      [self removeLight:rightLight];
  1751.      [self removeLight:leftLight];
  1752.      defaultLightsInUse = NO;
  1753.   }
  1754.   return self;
  1755. }
  1756.  
  1757.  
  1758. - removeLightNamed:(const char *)lightName
  1759. {
  1760.    int  i;
  1761.    id   light;
  1762.  
  1763.  
  1764.    for (i = 0; i < [lightList count]; i++)
  1765.    {  light = [lightList objectAt:i];
  1766.       if (!strcmp(lightName, [light shapeName]))
  1767.       {  [self removeLight:light];
  1768.          return self;
  1769.       }
  1770.    }
  1771.    return nil;
  1772. }
  1773.  
  1774.  
  1775. - setFieldOfViewByAngle:(float)viewAngle
  1776. {
  1777.   char   buf[128];
  1778.  
  1779.  
  1780.   [super setFieldOfViewByAngle:viewAngle];
  1781.   sprintf(buf, "%f", viewAngle);
  1782.   [tclInterp setVar2:"cam" :"fieldOfView" toValue:buf];
  1783.   [delegate cameraParametersWereUpdated:self];
  1784.  
  1785.   return self;
  1786. }
  1787.  
  1788.  
  1789. char *ReadOnlyWriteProc(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1790. {
  1791.   return "this is a read-only variable";
  1792. }
  1793.  
  1794.  
  1795. char *WriteProcForInterpolationProc(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1796. {
  1797.   // when a new interpolation proc is defined, there are several things we want to do.
  1798.   // first of all, we want to make sure that it's valid:
  1799.   // - a valid interpolation proc only has one argument: u
  1800.  
  1801.   // the other thing we might want to do is update the inspector panel (if we have one) about the contents of this guy...
  1802.  
  1803.   return NULL;
  1804. }
  1805.  
  1806.  
  1807. // someone is writing a new value for the cam(movingStyle) parameter, so we need
  1808. // to update the WW3DCamera to reflect that new value...
  1809. char *WriteProcForRenderStyle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1810. {
  1811.   char   *varString;
  1812.   id     me;
  1813.  
  1814.  
  1815.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1816.   me = [(WWTCLVarTrace *)clientData datum];
  1817.   if (varString)
  1818.   {  if (!strcmp(varString, "PointCloud"))
  1819.      {  [me setRenderStyle:N3D_PointCloud];
  1820.         return NULL;
  1821.      }
  1822.      if (!strcmp(varString, "WireFrame"))
  1823.      {  [me setRenderStyle:N3D_WireFrame];
  1824.         return NULL;
  1825.      }
  1826.      if (!strcmp(varString, "ShadedWireFrame"))
  1827.      {  [me setRenderStyle:N3D_ShadedWireFrame];
  1828.         return NULL;
  1829.      }
  1830.      if (!strcmp(varString, "FacetedSolids"))
  1831.      {  [me setRenderStyle:N3D_FacetedSolids];
  1832.         return NULL;
  1833.      }
  1834.      if (!strcmp(varString, "SmoothSolids"))
  1835.      {  [me setRenderStyle:N3D_SmoothSolids];
  1836.         return NULL;
  1837.      }
  1838.   }
  1839.   return "invalid value for \"cam(renderStyle)\"; must be on of PointCloud|WireFrame|ShadedWireFrame|FacetedSolids|SmoothSolids";
  1840. }
  1841.  
  1842.  
  1843. // someone is reading a value for the cam(renderStyle) parameter, so we need
  1844. // to " read-through" the WW3DCamera to reflect the current value...
  1845. char *ReadProcForRenderStyle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1846. {
  1847.   int    renderStyle;
  1848.   id     me;
  1849.  
  1850.  
  1851.   renderStyle = [[(WWTCLVarTrace *)clientData datum] renderStyle];
  1852.   me = [(WWTCLVarTrace *)clientData datum];
  1853.   if (renderStyle == N3D_PointCloud)
  1854.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"PointCloud"];
  1855.      return NULL;
  1856.   }
  1857.   if (renderStyle == N3D_WireFrame)
  1858.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"WireFrame"];
  1859.      return NULL;
  1860.   }
  1861.   if (renderStyle == N3D_ShadedWireFrame)
  1862.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"ShadedWireFrame"];
  1863.      return NULL;
  1864.   }
  1865.   if (renderStyle == N3D_FacetedSolids)
  1866.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"FacetedSolids"];
  1867.      return NULL;
  1868.   }
  1869.   if (renderStyle == N3D_SmoothSolids)
  1870.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"SmoothSolids"];
  1871.      return NULL;
  1872.   }
  1873.   
  1874.   return NULL;
  1875. }
  1876.  
  1877. // someone is writing a new value for the cam(movingStyle) parameter, so we need
  1878. // to update the WW3DCamera to reflect that new value...
  1879. char *WriteProcForMovingRenderStyle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1880. {
  1881.   char   *varString;
  1882.   id     me;
  1883.  
  1884.  
  1885.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1886.   me = [(WWTCLVarTrace *)clientData datum];
  1887.   if (varString)
  1888.   {  if (!strcmp(varString, "PointCloud"))
  1889.      {  [me setMovingRenderStyle:N3D_PointCloud];
  1890.         return NULL;
  1891.      }
  1892.      if (!strcmp(varString, "WireFrame"))
  1893.      {  [me setMovingRenderStyle:N3D_WireFrame];
  1894.         return NULL;
  1895.      }
  1896.      if (!strcmp(varString, "ShadedWireFrame"))
  1897.      {  [me setMovingRenderStyle:N3D_ShadedWireFrame];
  1898.         return NULL;
  1899.      }
  1900.      if (!strcmp(varString, "FacetedSolids"))
  1901.      {  [me setMovingRenderStyle:N3D_FacetedSolids];
  1902.         return NULL;
  1903.      }
  1904.      if (!strcmp(varString, "SmoothSolids"))
  1905.      {  [me setMovingRenderStyle:N3D_SmoothSolids];
  1906.         return NULL;
  1907.      }
  1908.   }
  1909.   return "invalid value for \"cam(movingRenderStyle)\"; must be on of PointCloud|WireFrame|ShadedWireFrame|FacetedSolids|SmoothSolids";
  1910. }
  1911.  
  1912.  
  1913. // someone is reading a value for the cam(MovingRenderStyle) parameter, so we need
  1914. // to " read-through" the WW3DCamera to reflect the current value...
  1915. char *ReadProcForMovingRenderStyle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1916. {
  1917.   int    movingRenderStyle;
  1918.  
  1919.  
  1920.   movingRenderStyle = [[(WWTCLVarTrace *)clientData datum] movingRenderStyle];
  1921.   if (movingRenderStyle == N3D_PointCloud)
  1922.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"PointCloud"];
  1923.      return NULL;
  1924.   }
  1925.   if (movingRenderStyle == N3D_WireFrame)
  1926.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"WireFrame"];
  1927.      return NULL;
  1928.   }
  1929.   if (movingRenderStyle == N3D_ShadedWireFrame)
  1930.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"ShadedWireFrame"];
  1931.      return NULL;
  1932.   }
  1933.   if (movingRenderStyle == N3D_FacetedSolids)
  1934.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"FacetedSolids"];
  1935.      return NULL;
  1936.   }
  1937.   if (movingRenderStyle == N3D_SmoothSolids)
  1938.   {  [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:"SmoothSolids"];
  1939.      return NULL;
  1940.   }
  1941.   
  1942.   return NULL;
  1943. }
  1944.  
  1945. // someone is writing a new value for the cam(tesselation) parameter, so we need
  1946. // to update the WW3DCamera to reflect that new value...
  1947. char *WriteProcForTesselation(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1948. {
  1949.   char   *varString;
  1950.   float  tesselation = 32.;
  1951.  
  1952.  
  1953.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1954.   sscanf(varString, "%f", &tesselation);
  1955.   [[(WWTCLVarTrace *)clientData datum] setTesselation:tesselation];
  1956.  
  1957.   return NULL;
  1958. }
  1959.  
  1960.  
  1961. // someone is reading a value for the cam(tesselation) parameter, so we need
  1962. // to " read-through" the WW3DCamera to reflect the current value...
  1963. char *ReadProcForTesselation(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1964. {
  1965.   char   buf[128];
  1966.   float  tesselation;
  1967.  
  1968.  
  1969.   tesselation = [[(WWTCLVarTrace *)clientData datum] tesselation];
  1970.   sprintf(buf, "%f", tesselation);
  1971.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  1972.  
  1973.   return NULL;
  1974. }
  1975.  
  1976. // someone is writing a new value for the cam(lowRezTesselation) parameter, so we need
  1977. // to update the WW3DCamera to reflect that new value...
  1978. char *WriteProcForLowRezTesselation(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1979. {
  1980.   char   *varString;
  1981.   float  lowRezTesselation = 16.;
  1982.  
  1983.  
  1984.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  1985.   sscanf(varString, "%f", &lowRezTesselation);
  1986.   [[(WWTCLVarTrace *)clientData datum] setLowRezTesselation:lowRezTesselation];
  1987.  
  1988.   return NULL;
  1989. }
  1990.  
  1991.  
  1992. // someone is reading a value for the cam(tesselation) parameter, so we need
  1993. // to " read-through" the WW3DCamera to reflect the current value...
  1994. char *ReadProcForLowRezTesselation(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  1995. {
  1996.   char   buf[128];
  1997.   float  lowRezTesselation;
  1998.  
  1999.  
  2000.   lowRezTesselation = [[(WWTCLVarTrace *)clientData datum] lowRezTesselation];
  2001.   sprintf(buf, "%f", lowRezTesselation);
  2002.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2003.  
  2004.   return NULL;
  2005. }
  2006.  
  2007. // someone is writing a new value for the cam(fieldOfView) parameter, so we need
  2008. // to update the WW3DCamera to reflect that new value...
  2009.  
  2010. // really should constrain fov to be from <0 && <180
  2011. char *WriteProcForFieldOfViewByAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2012. {
  2013.   char   *varString;
  2014.   float  fieldOfView = 45.;
  2015.  
  2016.  
  2017.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2018.   sscanf(varString, "%f", &fieldOfView);
  2019.   [[(WWTCLVarTrace *)clientData datum] setFieldOfViewByAngle:fieldOfView];
  2020.  
  2021.   return NULL;
  2022. }
  2023.  
  2024.  
  2025. // someone is reading a value for the cam(fieldOfView) parameter, so we need
  2026. // to " read-through" the WW3DCamera to reflect the current value...
  2027. char *ReadProcForFieldOfViewByAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2028. {
  2029.   char   buf[128];
  2030.   float  fieldOfView;
  2031.  
  2032.  
  2033.   fieldOfView = [[(WWTCLVarTrace *)clientData datum] fieldOfView];
  2034.   sprintf(buf, "%f", fieldOfView);
  2035.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2036.  
  2037.   return NULL;
  2038. }
  2039.  
  2040. - setEyeAt:(RtPoint)fromPoint toward:(RtPoint)toPoint roll:(float)aRollAngle;
  2041. {
  2042.   char   buf[384];
  2043.  
  2044.  
  2045.   [super setEyeAt:fromPoint toward:toPoint roll:aRollAngle];
  2046.  
  2047.   sprintf(buf, "%f %f %f", N3D_XComp(fromPoint), N3D_YComp(fromPoint), N3D_ZComp(fromPoint));
  2048.   [tclInterp setVar2:"cam" :"eyePoint" toValue:buf];
  2049.   sprintf(buf, "%f %f %f", N3D_XComp(toPoint), N3D_YComp(toPoint), N3D_ZComp(toPoint));
  2050.   [tclInterp setVar2:"cam" :"viewPoint" toValue:buf];
  2051.   sprintf(buf, "%f", aRollAngle);
  2052.   [tclInterp setVar2:"cam" :"rollAngle" toValue:buf];
  2053.  
  2054.   [delegate cameraParametersWereUpdated:self];
  2055.   return self;
  2056. }
  2057.  
  2058. // someone is writing a new value for the cam(eyePoint) parameter, so we need
  2059. // to update the WW3DCamera to reflect that new value...
  2060. char *WriteProcForEyePoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2061. {
  2062.   char     *varString, **argv;
  2063.   int      argc;
  2064.   RtPoint  anEyePoint, aViewPoint;
  2065.   RtFloat  aRollAngle;
  2066.  
  2067.  
  2068.   // get current values
  2069.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2070.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2071.   Tcl_SplitList(interp, varString, &argc, &argv); // fromPoint
  2072.   if (argc != 3)
  2073.   {  NXLogError("cam(eyePoint) should be a tcl list with 3 components, not <%s>\n", varString);
  2074.      if (argv) { free(argv); }
  2075.      return NULL;
  2076.   }
  2077.   N3D_XComp(anEyePoint) = (float)atof(argv[0]);
  2078.   N3D_YComp(anEyePoint) = (float)atof(argv[1]);
  2079.   N3D_ZComp(anEyePoint) = (float)atof(argv[2]);
  2080.   free(argv);
  2081.  
  2082.   [[(WWTCLVarTrace *)clientData datum] setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  2083.  
  2084.   return NULL;
  2085. }
  2086.  
  2087.  
  2088. // someone is reading a value for the cam() parameter, so we need
  2089. // to " read-through" the WW3DCamera to reflect the current value...
  2090. char *ReadProcForEyePoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2091. {
  2092.   char     buf[384];
  2093.   RtPoint  anEyePoint, aViewPoint;
  2094.   RtFloat  aRollAngle;
  2095.  
  2096.  
  2097.   // get current values
  2098.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2099.  
  2100.   sprintf(buf, "%f %f %f", N3D_XComp(anEyePoint), N3D_YComp(anEyePoint), N3D_ZComp(anEyePoint));
  2101.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2102.  
  2103.   return NULL;
  2104. }
  2105.  
  2106. // someone is writing a new value for the cam(viewPoint) parameter, so we need
  2107. // to update the WW3DCamera to reflect that new value...
  2108. char *WriteProcForViewPoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2109. {
  2110.   char     *varString, **argv;
  2111.   int      argc;
  2112.   RtPoint  anEyePoint, aViewPoint;
  2113.   RtFloat  aRollAngle;
  2114.  
  2115.  
  2116.   // get current values
  2117.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2118.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2119.   Tcl_SplitList(interp, varString, &argc, &argv); // viewPoint
  2120.   if (argc != 3)
  2121.   {  NXLogError("cam(viewPoint) should be a tcl list with 3 components, not <%s>\n", varString);
  2122.      if (argv) { free(argv); }
  2123.      return NULL;
  2124.   }
  2125.   N3D_XComp(aViewPoint) = (float)atof(argv[0]);
  2126.   N3D_YComp(aViewPoint) = (float)atof(argv[1]);
  2127.   N3D_ZComp(aViewPoint) = (float)atof(argv[2]);
  2128.   free(argv);
  2129.  
  2130.   [[(WWTCLVarTrace *)clientData datum] setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  2131.  
  2132.   return NULL;
  2133. }
  2134.  
  2135.  
  2136. // someone is reading a value for the cam(viewPoint) parameter, so we need
  2137. // to " read-through" the WW3DCamera to reflect the current value...
  2138. char *ReadProcForViewPoint(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2139. {
  2140.   char     buf[384];
  2141.   RtPoint  anEyePoint, aViewPoint;
  2142.   RtFloat  aRollAngle;
  2143.  
  2144.  
  2145.   // get current values
  2146.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2147.  
  2148.   sprintf(buf, "%f %f %f", N3D_XComp(aViewPoint), N3D_YComp(aViewPoint), N3D_ZComp(aViewPoint));
  2149.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2150.  
  2151.   return NULL;
  2152. }
  2153.  
  2154. // someone is writing a new value for the cam(rollAngle) parameter, so we need
  2155. // to update the WW3DCamera to reflect that new value...
  2156. char *WriteProcForRollAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2157. {
  2158.   char     *varString;
  2159.   RtPoint  anEyePoint, aViewPoint;
  2160.   RtFloat  aRollAngle;
  2161.  
  2162.  
  2163.   // get current values
  2164.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2165.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2166.   aRollAngle = (float)atof(varString);
  2167.  
  2168.   [[(WWTCLVarTrace *)clientData datum] setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  2169.  
  2170.   return NULL;
  2171. }
  2172.  
  2173.  
  2174. // someone is reading a value for the cam(rollAngle) parameter, so we need
  2175. // to " read-through" the WW3DCamera to reflect the current value...
  2176. char *ReadProcForRollAngle(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2177. {
  2178.   char     buf[384];
  2179.   RtPoint  anEyePoint, aViewPoint;
  2180.   RtFloat  aRollAngle;
  2181.  
  2182.  
  2183.   // get current values
  2184.   [[(WWTCLVarTrace *)clientData datum] getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2185.  
  2186.   sprintf(buf, "%f", aRollAngle);
  2187.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2188.  
  2189.   return NULL;
  2190. }
  2191.  
  2192.  
  2193. - (RtFloat)fStop { return fStop; }
  2194.  
  2195. - setFStop:(float)newFStop
  2196. {
  2197.   char   buf[128];
  2198.  
  2199.  
  2200.   fStop = newFStop;
  2201.   sprintf(buf, "%f", fStop);
  2202.   [tclInterp setVar2:"cam" :"fStop" toValue:buf];
  2203.   [delegate cameraParametersWereUpdated:self];
  2204.  
  2205.   return self;
  2206. }
  2207.  
  2208.  
  2209. // someone is writing a new value for the cam(fStop) parameter, so we need
  2210. // to update the WW3DCamera to reflect that new value...
  2211. char *WriteProcForFStop(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2212. {
  2213.   char   *varString;
  2214.   float  fStop = 1.0;
  2215.  
  2216.  
  2217.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2218.   sscanf(varString, "%f", &fStop);
  2219.   [[(WWTCLVarTrace *)clientData datum] setFStop:fStop];
  2220.  
  2221.   return NULL;
  2222. }
  2223.  
  2224.  
  2225. // someone is reading a value for the cam(fStop) parameter, so we need
  2226. // to " read-through" the WW3DCamera to reflect the current value...
  2227. char *ReadProcForFStop(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2228. {
  2229.   char   buf[128];
  2230.   float  fStop;
  2231.  
  2232.  
  2233.   fStop = [[(WWTCLVarTrace *)clientData datum] fStop];
  2234.   sprintf(buf, "%f", fStop);
  2235.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2236.  
  2237.   return NULL;
  2238. }
  2239.  
  2240. - (RtFloat)focalLength { return focalLength; }
  2241.  
  2242. - setFocalLength:(float)newFocalLength
  2243. {
  2244.   char   buf[128];
  2245.  
  2246.  
  2247.   focalLength = newFocalLength;
  2248.   sprintf(buf, "%f", focalLength);
  2249.   [tclInterp setVar2:"cam" :"focalLength" toValue:buf];
  2250.  
  2251.   [delegate cameraParametersWereUpdated:self];
  2252.  
  2253.   return self;
  2254. }
  2255.  
  2256.  
  2257. // someone is writing a new value for the cam(fStop) parameter, so we need
  2258. // to update the WW3DCamera to reflect that new value...
  2259. char *WriteProcForFocalLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2260. {
  2261.   char   *varString;
  2262.   float  focalLength = 1.0;
  2263.  
  2264.  
  2265.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2266.   sscanf(varString, "%f", &focalLength);
  2267.   [[(WWTCLVarTrace *)clientData datum] setFocalLength:focalLength];
  2268.  
  2269.   return NULL;
  2270. }
  2271.  
  2272.  
  2273. // someone is reading a value for the cam(fStop) parameter, so we need
  2274. // to " read-through" the WW3DCamera to reflect the current value...
  2275. char *ReadProcForFocalLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2276. {
  2277.   char   buf[128];
  2278.   float  focalLength;
  2279.  
  2280.  
  2281.   focalLength = [[(WWTCLVarTrace *)clientData datum] focalLength];
  2282.   sprintf(buf, "%f", focalLength);
  2283.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2284.  
  2285.   return NULL;
  2286. }
  2287.  
  2288.  
  2289. - (RtFloat)focalDistance { return focalDistance; }
  2290.  
  2291. - setFocalDistance:(float)newFocalDistance
  2292. {
  2293.   char   buf[128];
  2294.  
  2295.  
  2296.   if (newFocalDistance > 0)
  2297.   {  focalDistance = newFocalDistance;
  2298.      sprintf(buf, "%f", focalDistance);
  2299.      [tclInterp setVar2:"cam" :"focalDistance" toValue:buf];
  2300.  
  2301.      [delegate cameraParametersWereUpdated:self];
  2302.   }
  2303.  
  2304.   return self;
  2305. }
  2306.  
  2307.  
  2308. // someone is writing a new value for the cam(focalDistance) parameter, so we need
  2309. // to update the WW3DCamera to reflect that new value...
  2310. char *WriteProcForFocalDistance(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2311. {
  2312.   char   *varString;
  2313.   float  focalDistance = 1.0;
  2314.  
  2315.  
  2316.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2317.   sscanf(varString, "%f", &focalDistance);
  2318.   [[(WWTCLVarTrace *)clientData datum] setFocalDistance:focalDistance];
  2319.  
  2320.   return NULL;
  2321. }
  2322.  
  2323.  
  2324. // someone is reading a value for the cam(focalDistance) parameter, so we need
  2325. // to " read-through" the WW3DCamera to reflect the current value...
  2326. char *ReadProcForFocalDistance(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2327. {
  2328.   char   buf[128];
  2329.   float  focalDistance;
  2330.  
  2331.  
  2332.   focalDistance = [[(WWTCLVarTrace *)clientData datum] focalDistance];
  2333.   sprintf(buf, "%f", focalDistance);
  2334.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2335.  
  2336.   return NULL;
  2337. }
  2338.  
  2339. - setFrameNumber:(int)aFrameNumber
  2340. {
  2341.   char   buf[128];
  2342.  
  2343.  
  2344.   if ((aFrameNumber <= [self endFrame]) && ([self frameNumber] != aFrameNumber))  //it's valid and it's new
  2345.   {  // if it's actually a new frame, we need to flip the "evaluateInterpProc"
  2346.      // flag, so that the next time we render, we run the camera interpolation routine...
  2347.      evaluateInterpProc = YES;
  2348.   }
  2349.  
  2350.   // we assume that the [super setFrameNumber:]  clamps to endFrameNumber
  2351.   [super setFrameNumber:aFrameNumber];
  2352.  
  2353.   // by setting the frame number, we need to make sure that all the
  2354.   // appropriate other parts of the camera have been updated.  What
  2355.   // automatically follows along?  Well, the shutterOpenTime needs to get
  2356.   // updated, at least...
  2357.   [self setShutterOpenTime:(shotStartTime + (frameNumber * frameTimeIncrement))];
  2358.  
  2359.   sprintf(buf, "%d", frameNumber);
  2360.   [tclInterp setVar2:"cam" :"frameNumber" toValue:buf];
  2361.   [delegate cameraParametersWereUpdated:self];
  2362.  
  2363.   return self;
  2364. }
  2365.  
  2366.  
  2367. - resetFrameNumber
  2368. {
  2369.   [self setFrameNumber:0];
  2370.   return self;
  2371. }
  2372.  
  2373. // someone is writing a new value for the cam(frameNumber) parameter, so we need
  2374. // to update the WW3DCamera to reflect that new value...
  2375. char *WriteProcForFrameNumber(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2376. {
  2377.   char   *varString;
  2378.   int    frameNumber = 1;
  2379.  
  2380.  
  2381.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2382.  
  2383.   // frameNumber has to be an integer
  2384.  
  2385.  
  2386.   sscanf(varString, "%d", &frameNumber);
  2387.   [[(WWTCLVarTrace *)clientData datum] setFrameNumber:frameNumber];
  2388.  
  2389.   return NULL;
  2390. }
  2391.  
  2392.  
  2393. // someone is reading a value for the cam(frameNumber) parameter, so we need
  2394. // to " read-through" the WW3DCamera to reflect the current value...
  2395. char *ReadProcForFrameNumber(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2396. {
  2397.   char   buf[128];
  2398.   int    frameNumber;
  2399.  
  2400.  
  2401.   frameNumber = [[(WWTCLVarTrace *)clientData datum] frameNumber];
  2402.   sprintf(buf, "%d", frameNumber);
  2403.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2404.  
  2405.   return NULL;
  2406. }
  2407.  
  2408. // whenever the frame number or the frameTimeIncrement gets changed,
  2409. // the open and close time need to be recalculated
  2410.  
  2411. - (RtFloat)shutterOpenTime { return shutterOpenTime; }
  2412.  
  2413. - setShutterOpenTime:(RtFloat)newShutterOpenTime
  2414. {
  2415.   char   buf[128];
  2416.  
  2417.  
  2418.   shutterOpenTime = newShutterOpenTime;
  2419.   sprintf(buf, "%f", shutterOpenTime);
  2420.   [tclInterp setVar2:"cam" :"shutterOpenTime" toValue:buf];
  2421.   [delegate cameraParametersWereUpdated:self];
  2422.  
  2423.   return self;
  2424. }
  2425.  
  2426.  
  2427. // someone is writing a new value for the cam(shutterOpenTime) parameter, so we need
  2428. // to update the WW3DCamera to reflect that new value...
  2429. char *WriteProcForShutterOpenTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2430. {
  2431.   char   *varString;
  2432.   RtFloat  shutterOpenTime = 0.0;
  2433.  
  2434.  
  2435.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2436.   sscanf(varString, "%f", &shutterOpenTime);
  2437.   [[(WWTCLVarTrace *)clientData datum] setShutterOpenTime:shutterOpenTime];
  2438.  
  2439.   return NULL;
  2440. }
  2441.  
  2442.  
  2443. // someone is reading a value for the cam(shutterOpenTime) parameter, so we need
  2444. // to " read-through" the WW3DCamera to reflect the current value...
  2445. char *ReadProcForShutterOpenTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2446. {
  2447.   char   buf[128];
  2448.   RtFloat  shutterOpenTime;
  2449.  
  2450.  
  2451.   shutterOpenTime = [[(WWTCLVarTrace *)clientData datum] shutterOpenTime];
  2452.   sprintf(buf, "%f", shutterOpenTime);
  2453.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2454.  
  2455.   return NULL;
  2456. }
  2457.  
  2458. - (RtFloat)shutterCloseTime 
  2459.    if (shooting)
  2460.    {  return (shutterOpenTime + (exposureLength * exposureLengthFactor)); 
  2461.    }
  2462.    // it's a still frame; no need to modulate the exposure length...
  2463.    return (shutterOpenTime + exposureLength);
  2464. }
  2465.  
  2466. // someone is writing a new value for the cam(shutterCloseTime) parameter, so we need
  2467. // to update the WW3DCamera to reflect that new value...
  2468. char *WriteProcForShutterCloseTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2469. {
  2470.   return "cam(shutterCloseTime) is read-only";
  2471. }
  2472.  
  2473.  
  2474. // someone is reading a value for the cam(shutterCloseTime) parameter, so we need
  2475. // to " read-through" the WW3DCamera to reflect the current value...
  2476. char *ReadProcForShutterCloseTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2477. {
  2478.   char   buf[128];
  2479.   RtFloat  shutterCloseTime;
  2480.  
  2481.  
  2482.   shutterCloseTime = [[(WWTCLVarTrace *)clientData datum] shutterCloseTime];
  2483.   sprintf(buf, "%f", shutterCloseTime);
  2484.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2485.  
  2486.   return NULL;
  2487. }
  2488.  
  2489. - (float)frameTimeIncrement { return frameTimeIncrement; }
  2490.  
  2491. - (float)exposureLength { return exposureLength; }
  2492.  
  2493. - setExposureLength:(float)newExposureLength
  2494. {
  2495.   char   buf[128];
  2496.  
  2497.   // need to make sure that the new exposure length is consistent with the rest of the camera
  2498.   // what does this mean?
  2499.   // the length of the exposure cannot be longer than the interval between frames, i.e. 
  2500.   // exposureLength <= (frameTimeIncrement == 1./framesPerSecond)
  2501.   // 
  2502.   //NXLogError("newExposureLength == %f\n", newExposureLength);
  2503.  
  2504.   if (newExposureLength < 0.0)
  2505.   {  NXLogError("exposureLength must be a positive number, not %f\n", newExposureLength);
  2506.      return nil;
  2507.   }
  2508.  
  2509.   // actually, we only want to do this if we're shooting.  Anyway, at
  2510.   // the start of shooting a shot (i.e. an ordered sequence), we should
  2511.   // sanity check then - this might be perfectly reasonable for a still
  2512.   // frame...
  2513.   if (shooting)
  2514.   {  if (newExposureLength > [self frameTimeIncrement])
  2515.      {  exposureLength = [self frameTimeIncrement];
  2516.      }
  2517.      else
  2518.      {  exposureLength = newExposureLength;
  2519.      }
  2520.   }
  2521.   else  // don't do a clip; it could be whatever positive value they want...
  2522.   {  exposureLength = newExposureLength;
  2523.   }
  2524.   sprintf(buf, "%f", exposureLength);
  2525.   [tclInterp setVar2:"cam" :"exposureLength" toValue:buf];
  2526.   [delegate cameraParametersWereUpdated:self];
  2527.   justResetExposureLength = YES;
  2528.  
  2529.  
  2530.   return self;
  2531. }
  2532.  
  2533.  
  2534. // someone is writing a new value for the cam(exposureLength) parameter, so we need
  2535. // to update the WW3DCamera to reflect that new value...
  2536. char *WriteProcForExposureLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2537. {
  2538.   char   *varString;
  2539.   RtFloat  exposureLength = 0.0;
  2540.  
  2541.  
  2542.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2543.   sscanf(varString, "%f", &exposureLength);
  2544.   [[(WWTCLVarTrace *)clientData datum] setExposureLength:exposureLength];
  2545.  
  2546.   return NULL;
  2547. }
  2548.  
  2549.  
  2550. // someone is reading a value for the cam(exposureLength) parameter, so we need
  2551. // to " read-through" the WW3DCamera to reflect the current value...
  2552. char *ReadProcForExposureLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2553. {
  2554.   char   buf[128];
  2555.   RtFloat  exposureLength;
  2556.  
  2557.  
  2558.   exposureLength = [[(WWTCLVarTrace *)clientData datum] exposureLength];
  2559.   sprintf(buf, "%f", exposureLength);
  2560.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2561.  
  2562.   return NULL;
  2563. }
  2564.  
  2565. - (float)framesPerSecond { return framesPerSecond; }
  2566.  
  2567. - setFramesPerSecond:(float)newFramesPerSecond
  2568. {
  2569.   char     buf[128];
  2570.   RtFloat  maxExposureLength;
  2571.   int      newEndFrame;
  2572.  
  2573.  
  2574.   // okay, the frames/second is being changed.  
  2575.   // what do we need to update?
  2576.   // we want the duration of the shot (in seconds) to stay the same, 
  2577.   // so we need to:
  2578.   // - make sure that the exposureLength is still valid; if not, clamp it
  2579.   // - reset the startFrame to 0 and the endFrame to whatever is appropriate 
  2580.  
  2581.   framesPerSecond = newFramesPerSecond;
  2582.   sprintf(buf, "%f", newFramesPerSecond);
  2583.   [tclInterp setVar2:"cam" :"FramesPerSecond" toValue:buf];
  2584.  
  2585.   frameTimeIncrement = (1.0/framesPerSecond);
  2586.   maxExposureLength = frameTimeIncrement;
  2587.  
  2588.   // if, by changing the frame rate, we've invalidated the current
  2589.   // setting for how long the shutter stays open for each frame, we need to
  2590.   // reset it to a valid value.  If it's still valid, leave it be (i.e. if
  2591.   // it was a strobe camera, it will stay that way).
  2592.   // uh, no.  There are two normal cases: keep the exposureLength at 0.0, for a strobe,
  2593.   // or keep the exposureLength == frameTimeIncrement.  So... if they want a special
  2594.   // setting, they'll need to reset it after setting a new fps.
  2595.   // uh, no I changed my mind again.  If they want a *strobe*, they have to reset it explicitly
  2596.   // this is what I want in most cases (i.e. I want motion blur)
  2597.   [self setExposureLength:maxExposureLength];
  2598.  
  2599.   newEndFrame = (framesPerSecond * [self shotLength]); // actually should do the right thing at the half frame mark...
  2600.   [super setStartFrame:0 endFrame:newEndFrame incrementFramesBy:[self frameIncrement]];
  2601.  
  2602.   [delegate cameraParametersWereUpdated:self];
  2603.  
  2604.   return self;
  2605. }
  2606.  
  2607.  
  2608. // someone is writing a new value for the cam(framesPerSecond) parameter, so we need
  2609. // to update the WW3DCamera to reflect that new value...
  2610. char *WriteProcForFramesPerSecond(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2611. {
  2612.   char   *varString;
  2613.   float  framesPerSecond = 17.0;
  2614.  
  2615.  
  2616.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2617.  
  2618.   // framesPerSecond has to be a float
  2619.   sscanf(varString, "%f", &framesPerSecond);
  2620.   [[(WWTCLVarTrace *)clientData datum] setFramesPerSecond:framesPerSecond];
  2621.  
  2622.   return NULL;
  2623. }
  2624.  
  2625.  
  2626. // someone is reading a value for the cam(framesPerSecond) parameter, so we need
  2627. // to " read-through" the WW3DCamera to reflect the current value...
  2628. char *ReadProcForFramesPerSecond(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2629. {
  2630.   char   buf[128];
  2631.   float  framesPerSecond;
  2632.  
  2633.  
  2634.   framesPerSecond = [[(WWTCLVarTrace *)clientData datum] framesPerSecond];
  2635.   sprintf(buf, "%f", framesPerSecond);
  2636.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2637.  
  2638.   return NULL;
  2639. }
  2640.  
  2641. - (float)shotLength { return shotLength; }
  2642.  
  2643. - setShotLength:(float)newShotLength
  2644. {
  2645.   char     buf[128];
  2646.   int      newEndFrame;
  2647.  
  2648.  
  2649.   // okay, the frames/second is being changed.  
  2650.   // what do we need to update?
  2651.   // - reset the startFrame to 0 and the endFrame to whatever is appropriate 
  2652.  
  2653.   shotLength = newShotLength;
  2654.   sprintf(buf, "%f", newShotLength);
  2655.   [tclInterp setVar2:"cam" :"shotLength" toValue:buf];
  2656.  
  2657.   newEndFrame = (shotLength * [self framesPerSecond]) - 1; // actually should the right thing at the half frame mark...
  2658.   [super setStartFrame:0 endFrame:newEndFrame incrementFramesBy:[self frameIncrement]];
  2659.  
  2660.   [delegate cameraParametersWereUpdated:self];
  2661.  
  2662.   return self;
  2663. }
  2664.  
  2665.  
  2666. // someone is writing a new value for the cam(shotLength) parameter, so we need
  2667. // to update the WW3DCamera to reflect that new value...
  2668. char *WriteProcForShotLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2669. {
  2670.   char   *varString;
  2671.   float  shotLength = 17.0;
  2672.  
  2673.  
  2674.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2675.  
  2676.   // ShotLength has to be a float
  2677.   sscanf(varString, "%f", &shotLength);
  2678.   [[(WWTCLVarTrace *)clientData datum] setShotLength:shotLength];
  2679.  
  2680.   return NULL;
  2681. }
  2682.  
  2683.  
  2684. // someone is reading a value for the cam(ShotLength) parameter, so we need
  2685. // to " read-through" the WW3DCamera to reflect the current value...
  2686. char *ReadProcForShotLength(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2687. {
  2688.   char   buf[128];
  2689.   float  shotLength;
  2690.  
  2691.  
  2692.   shotLength = [[(WWTCLVarTrace *)clientData datum] shotLength];
  2693.   sprintf(buf, "%f", shotLength);
  2694.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2695.  
  2696.   return NULL;
  2697. }
  2698.  
  2699. - (float)shotStartTime { return shotStartTime; }
  2700.  
  2701. - setShotStartTime:(float)newShotStartTime
  2702. {
  2703.   char     buf[128];
  2704.  
  2705.  
  2706.   shotStartTime = newShotStartTime;
  2707.   sprintf(buf, "%f", newShotStartTime);
  2708.   [tclInterp setVar2:"cam" :"shotStartTime" toValue:buf];
  2709.  
  2710.   [delegate cameraParametersWereUpdated:self];
  2711.  
  2712.   return self;
  2713. }
  2714.  
  2715.  
  2716. // someone is writing a new value for the cam(shotStartTime) parameter, so we need
  2717. // to update the WW3DCamera to reflect that new value...
  2718. char *WriteProcForShotStartTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2719. {
  2720.   char   *varString;
  2721.   float  shotStartTime = 0.0;
  2722.  
  2723.  
  2724.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2725.  
  2726.   // ShotStartTime has to be a float
  2727.   sscanf(varString, "%f", &shotStartTime);
  2728.   [[(WWTCLVarTrace *)clientData datum] setShotStartTime:shotStartTime];
  2729.  
  2730.   return NULL;
  2731. }
  2732.  
  2733.  
  2734. // someone is reading a value for the cam(shotStartTime) parameter, so we need
  2735. // to " read-through" the WW3DCamera to reflect the current value...
  2736. char *ReadProcForShotStartTime(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2737. {
  2738.   char   buf[128];
  2739.   float  shotStartTime;
  2740.  
  2741.  
  2742.   shotStartTime = [[(WWTCLVarTrace *)clientData datum] shotStartTime];
  2743.   sprintf(buf, "%f", shotStartTime);
  2744.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2745.  
  2746.   return NULL;
  2747. }
  2748.  
  2749. - (float)exposureLengthFactor { return exposureLengthFactor; }
  2750.  
  2751. - setExposureLengthFactor:(float)newExposureLengthFactor
  2752. {
  2753.   char     buf[128];
  2754.  
  2755.  
  2756.   exposureLengthFactor = newExposureLengthFactor;
  2757.   // bound it inclusively between 0 and 1
  2758.   if (exposureLengthFactor < 0.0)
  2759.   {  exposureLengthFactor = 0.0;
  2760.   }
  2761.   if (exposureLengthFactor > 1.0)
  2762.   {  exposureLengthFactor = 1.0;
  2763.   }
  2764.   sprintf(buf, "%f", newExposureLengthFactor);
  2765.   [tclInterp setVar2:"cam" :"exposureLengthFactor" toValue:buf];
  2766.  
  2767.   [delegate cameraParametersWereUpdated:self];
  2768.  
  2769.   return self;
  2770. }
  2771.  
  2772.  
  2773. // someone is writing a new value for the cam(exposureLengthFactor) parameter, so we need
  2774. // to update the WW3DCamera to reflect that new value...
  2775. char *WriteProcForExposureLengthFactor(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2776. {
  2777.   char   *varString;
  2778.   float  exposureLengthFactor = 0.0;
  2779.  
  2780.  
  2781.   varString = [[(WWTCLVarTrace *)clientData tclInterp] getVar2:name1 :name2];
  2782.  
  2783.   // exposureLengthFactor has to be a float
  2784.   sscanf(varString, "%f", &exposureLengthFactor);
  2785.   [[(WWTCLVarTrace *)clientData datum] setExposureLengthFactor:exposureLengthFactor];
  2786.  
  2787.   return NULL;
  2788. }
  2789.  
  2790.  
  2791. // someone is reading a value for the cam(exposureLengthFactor) parameter, so we need
  2792. // to " read-through" the WW3DCamera to reflect the current value...
  2793. char *ReadProcForExposureLengthFactor(ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags)
  2794. {
  2795.   char   buf[128];
  2796.   float  exposureLengthFactor;
  2797.  
  2798.  
  2799.   exposureLengthFactor = [[(WWTCLVarTrace *)clientData datum] exposureLengthFactor];
  2800.   sprintf(buf, "%f", exposureLengthFactor);
  2801.   [[(WWTCLVarTrace *)clientData tclInterp] setVar2:name1 :name2 toValue:buf];
  2802.  
  2803.   return NULL;
  2804. }
  2805.  
  2806. - (BOOL)shooting { return shooting; }
  2807.  
  2808. - setShooting:(BOOL)newShooting
  2809. {
  2810.   if (shooting && !newShooting)
  2811.   {  justFinishedShooting = YES;
  2812.   }
  2813.   shooting = newShooting;
  2814.  
  2815.   return self;
  2816. }
  2817.  
  2818. - takeShooting:sender
  2819. {
  2820.   [self setShooting:(BOOL)[sender intValue]];
  2821.   return self;
  2822. }
  2823.  
  2824. // in this routine, the tcl interp is assumed to have the correct values, and so the camera has to conform to it...
  2825. // cam(fieldOfView) : fieldOfView : float -> float
  2826. // cam(eyePoint) : eyePoint : RtPoint -> {x y z}
  2827. // cam(viewPoint) : viewPoint : RtPoint -> {x y z}
  2828. // cam(rollAngle) : rollAngle : float -> float
  2829. // cam(fStop) : fStop : float -> float
  2830. // cam(focalLength) : focalLength : float -> float
  2831. // cam(focalDistance) : focalDistance : float -> float
  2832. // cam(frameNumber) : frameNumber : int -> int
  2833. // cam(tesselation)
  2834. // cam(lowRezTesselation)
  2835. // cam(renderStyle) : 
  2836. // cam(movingRenderStyle) : 
  2837.  
  2838. // NOT DONE YET!
  2839. // cam(pixelAspectRatio) : pixelAspectRatio : float -> float
  2840. // cam(projectionType) : projectionType : N3DProjectionType -> string
  2841. // cam(backgroundColor) : backgroundColor : NXColor -> {r g b}
  2842. // cam(doesDrawBackgroundColor) : doesDrawBackgroundColor : BOOL -> int
  2843. // cam(nearPlane) : nearPlane : float -> float
  2844. // cam(farPlane) : farPlane : float -> float
  2845.  
  2846.  
  2847. // need to talk about interdependencies of these variables...
  2848. // send mail to Dan at Pixar and ask, especially about fStop, focalLength, and focalDistance...
  2849.  
  2850. - setupTraces
  2851. {
  2852.   char         *valAsString, *varName;
  2853.   RtPoint      anEyePoint, aViewPoint;
  2854.   RtFloat      aRollAngle;
  2855.  
  2856.  
  2857.   valAsString = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  2858.   varName = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  2859.  
  2860.   // need to pull out my current camera parameters and send them as
  2861.   // "set cam(paramName) paramValue" to my interp here...
  2862.   // and then we need to set up read and write traces so that any set calls
  2863.   // on any cam() variable will be in synch with this instance...
  2864.   
  2865.  
  2866.   // you may be asking yourself here: "why is wave, that bozo, copying
  2867.   // the strings that correspond to the variables names into a tmp
  2868.   // variable?  Is he really that wasteful, just because he has bigger
  2869.   // and more expensive equipment than I do?  Is he intentionally wasting
  2870.   // my precious time?"  Well, sports fans, no.  The problem is that
  2871.   // the current (7.3) implementation of tcl still uses a performance
  2872.   // hack that gets bit by compilers being smart.  The short answer is
  2873.   // if you hand tcl a const char* that the compiler has squirreled away
  2874.   // somewhere in read-only space, you will dump core, because tcl,
  2875.   // while doing a comparison on array elements, attempts to stick a '\0'
  2876.   // where the '(' is so it can do a fast hash table lookup.  It's very
  2877.   // good about taking the '\0' out once its done, but unfortunately, 
  2878.   // you'll never get the chance...  This is reasonably well documented
  2879.   // in the tcl doc, and given the efficiency, I can't really complain,
  2880.   // but it *is* a bug (whether in C, the compiler, or tcl, you make the call).
  2881.   // Anyway, to get around it, you either use the setVar2 version, or
  2882.   // you make sure that the string you hand into setVar is writable.
  2883.   // gak...
  2884.  
  2885.   // 
  2886.   strcpy(varName, "cam(renderStyle)");
  2887.   strcpy(varName, "SmoothSolids"); // do a default
  2888.   if ([self renderStyle] == N3D_PointCloud)
  2889.   {  strcpy(valAsString, "PointCloud");
  2890.   }
  2891.   if (renderStyle == N3D_WireFrame)
  2892.   {  strcpy(valAsString, "WireFrame");
  2893.   }
  2894.   if (renderStyle == N3D_ShadedWireFrame)
  2895.   {  strcpy(valAsString, "ShadedWireFrame");
  2896.   }
  2897.   if (renderStyle == N3D_FacetedSolids)
  2898.   {  strcpy(valAsString, "FacetedSolids");
  2899.   }
  2900.   if (renderStyle == N3D_SmoothSolids)
  2901.   {  strcpy(valAsString, "SmoothSolids");
  2902.   }
  2903.   [tclInterp setVar:varName toValue:valAsString];
  2904.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForRenderStyle usingData:(ClientData)self];
  2905.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForRenderStyle usingData:(ClientData)self];
  2906.  
  2907.   // 
  2908.   strcpy(varName, "cam(movingRenderStyle)");
  2909.   strcpy(varName, "FacetedSolids"); // do a default
  2910.   if ([self movingRenderStyle] == N3D_PointCloud)
  2911.   {  strcpy(valAsString, "PointCloud");
  2912.   }
  2913.   if (movingRenderStyle == N3D_WireFrame)
  2914.   {  strcpy(valAsString, "WireFrame");
  2915.   }
  2916.   if (movingRenderStyle == N3D_ShadedWireFrame)
  2917.   {  strcpy(valAsString, "ShadedWireFrame");
  2918.   }
  2919.   if (movingRenderStyle == N3D_FacetedSolids)
  2920.   {  strcpy(valAsString, "FacetedSolids");
  2921.   }
  2922.   if (movingRenderStyle == N3D_SmoothSolids)
  2923.   {  strcpy(valAsString, "SmoothSolids");
  2924.   }
  2925.   [tclInterp setVar:varName toValue:valAsString];
  2926.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForMovingRenderStyle usingData:(ClientData)self];
  2927.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForMovingRenderStyle usingData:(ClientData)self];
  2928.  
  2929.   // 
  2930.   strcpy(varName, "cam(tesselation)");
  2931.   sprintf(valAsString, "%f", [self tesselation]); // turn the value into its tcl equivalent
  2932.   [tclInterp setVar:varName toValue:valAsString];
  2933.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForTesselation usingData:(ClientData)self];
  2934.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForTesselation usingData:(ClientData)self];
  2935.  
  2936.   // 
  2937.   strcpy(varName, "cam(lowRezTesselation)");
  2938.   sprintf(valAsString, "%f", [self lowRezTesselation]); // turn the value into its tcl equivalent
  2939.   [tclInterp setVar:varName toValue:valAsString];
  2940.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForLowRezTesselation usingData:(ClientData)self];
  2941.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForLowRezTesselation usingData:(ClientData)self];
  2942.  
  2943.   // 
  2944.   strcpy(varName, "cam(fieldOfView)");
  2945.   sprintf(valAsString, "%f", [self fieldOfView]); // turn the value into its tcl equivalent
  2946.   [tclInterp setVar:varName toValue:valAsString];
  2947.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFieldOfViewByAngle usingData:(ClientData)self];
  2948.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFieldOfViewByAngle usingData:(ClientData)self];
  2949.  
  2950.   //
  2951.   [self getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2952.  
  2953.   strcpy(varName, "cam(eyePoint)");
  2954.   sprintf(valAsString, "%f %f %f", N3D_XComp(anEyePoint), N3D_YComp(anEyePoint), N3D_ZComp(anEyePoint));
  2955.   [tclInterp setVar:varName toValue:valAsString];
  2956.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForEyePoint usingData:(ClientData)self];
  2957.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForEyePoint usingData:(ClientData)self];
  2958.  
  2959.   strcpy(varName, "cam(viewPoint)");
  2960.   sprintf(valAsString, "%f %f %f", N3D_XComp(aViewPoint), N3D_YComp(aViewPoint), N3D_ZComp(aViewPoint));
  2961.   [tclInterp setVar:varName toValue:valAsString];
  2962.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForViewPoint usingData:(ClientData)self];
  2963.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForViewPoint usingData:(ClientData)self];
  2964.  
  2965.   strcpy(varName, "cam(rollAngle)");
  2966.   sprintf(valAsString, "%f", aRollAngle); // turn the value into its tcl equivalent
  2967.   [tclInterp setVar:varName toValue:valAsString];
  2968.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForRollAngle usingData:(ClientData)self];
  2969.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForRollAngle usingData:(ClientData)self];
  2970.  
  2971.   // 
  2972.   strcpy(varName, "cam(fStop)");
  2973.   sprintf(valAsString, "%f", [self fStop]); // turn the value into its tcl equivalent
  2974.   [tclInterp setVar:varName toValue:valAsString];
  2975.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFStop usingData:(ClientData)self];
  2976.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFStop usingData:(ClientData)self];
  2977.   // 
  2978.   strcpy(varName, "cam(focalLength)");
  2979.   sprintf(valAsString, "%f", [self focalLength]); // turn the value into its tcl equivalent
  2980.   [tclInterp setVar:varName toValue:valAsString];
  2981.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFocalLength usingData:(ClientData)self];
  2982.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFocalLength usingData:(ClientData)self];
  2983.   // 
  2984.   strcpy(varName, "cam(focalDistance)");
  2985.   sprintf(valAsString, "%f", [self focalDistance]); // turn the value into its tcl equivalent
  2986.   [tclInterp setVar:varName toValue:valAsString];
  2987.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFocalDistance usingData:(ClientData)self];
  2988.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFocalDistance usingData:(ClientData)self];
  2989.   // 
  2990.   strcpy(varName, "cam(frameNumber)");
  2991.   sprintf(valAsString, "%d", [self frameNumber]); // turn the value into its tcl equivalent
  2992.   [tclInterp setVar:varName toValue:valAsString];
  2993.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFrameNumber usingData:(ClientData)self];
  2994.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFrameNumber usingData:(ClientData)self];
  2995.   // 
  2996.   strcpy(varName, "cam(shotLength)");
  2997.   sprintf(valAsString, "%f", [self shotLength]); // turn the value into its tcl equivalent
  2998.   [tclInterp setVar:varName toValue:valAsString];
  2999.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShotLength usingData:(ClientData)self];
  3000.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShotLength  usingData:(ClientData)self];
  3001.   // 
  3002.   strcpy(varName, "cam(shotStartTime)");
  3003.   sprintf(valAsString, "%f", [self shotStartTime]); // turn the value into its tcl equivalent
  3004.   [tclInterp setVar:varName toValue:valAsString];
  3005.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShotStartTime usingData:(ClientData)self];
  3006.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShotStartTime  usingData:(ClientData)self];
  3007.   // 
  3008.   strcpy(varName, "cam(framesPerSecond)");
  3009.   sprintf(valAsString, "%f", [self framesPerSecond]); // turn the value into its tcl equivalent
  3010.   [tclInterp setVar:varName toValue:valAsString];
  3011.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForFramesPerSecond usingData:(ClientData)self];
  3012.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForFramesPerSecond usingData:(ClientData)self];
  3013.   // 
  3014.   strcpy(varName, "cam(exposureLengthFactor)");
  3015.   sprintf(valAsString, "%f", [self exposureLengthFactor]); // turn the value into its tcl equivalent
  3016.   [tclInterp setVar:varName toValue:valAsString];
  3017.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForExposureLengthFactor usingData:(ClientData)self];
  3018.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForExposureLengthFactor usingData:(ClientData)self];
  3019.   // 
  3020.   strcpy(varName, "cam(shutterOpenTime)");
  3021.   sprintf(valAsString, "%f", [self shutterOpenTime]); // turn the value into its tcl equivalent
  3022.   [tclInterp setVar:varName toValue:valAsString];
  3023.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShutterOpenTime usingData:(ClientData)self];
  3024.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShutterOpenTime usingData:(ClientData)self];
  3025.   // 
  3026.   strcpy(varName, "cam(shutterCloseTime)");
  3027.   sprintf(valAsString, "%f", [self shutterCloseTime]); // turn the value into its tcl equivalent
  3028.   [tclInterp setVar:varName toValue:valAsString];
  3029.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForShutterCloseTime usingData:(ClientData)self];
  3030.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForShutterCloseTime usingData:(ClientData)self];
  3031.   // 
  3032.   strcpy(varName, "cam(exposureLength)");
  3033.   sprintf(valAsString, "%f", [self exposureLength]); // turn the value into its tcl equivalent
  3034.   [tclInterp setVar:varName toValue:valAsString];
  3035.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForExposureLength usingData:(ClientData)self];
  3036.   [tclInterp traceReadsOn:varName andCall:(Tcl_VarTraceProc *)ReadProcForExposureLength usingData:(ClientData)self];
  3037.   // 
  3038.   // 
  3039.   strcpy(varName, "cam(interpolationProc)");
  3040.   // need to set up a default interpolation proc...
  3041.   sprintf(valAsString, "noop");
  3042.   [tclInterp setVar:varName toValue:valAsString];
  3043.   [tclInterp traceWritesOn:varName andCall:(Tcl_VarTraceProc *)WriteProcForInterpolationProc usingData:(ClientData)self];
  3044.  
  3045.   // continue for all variables...
  3046.  
  3047.  
  3048.   inSynchWithTclInterp = YES;
  3049.   NXZoneFree([self zone], valAsString);
  3050.   NXZoneFree([self zone], varName);
  3051.  
  3052.  
  3053.   return self;
  3054. }
  3055.  
  3056.  
  3057. - initFrame:(const NXRect *)r 
  3058. {
  3059.    RtPoint fromP = {0,0,-5.0}, toP = {0,0,0};
  3060.    id aShape;
  3061.  
  3062.  
  3063.    [super initFrame:r];
  3064.  
  3065.    // speed stuff up and help workaround HP 3.2 bug (32 bit w/qrman crashes WS)
  3066.    [self setOpaque:YES];
  3067.  
  3068.    tclInterp = [[WWInterp alloc] init];
  3069.  
  3070.    [self initInterp];
  3071.  
  3072.    renderStyle = N3D_SmoothSolids;
  3073.    movingRenderStyle = N3D_FacetedSolids;
  3074.  
  3075.    scaleUpFactor = 1.05;
  3076.    scaleDownFactor = 0.95;
  3077.    translateXFactor = 0.01;
  3078.    translateYFactor = 0.01;
  3079.    translateZFactor = 0.05;
  3080.    epsilon = 4.0;
  3081.    selectionWidthEpsilon = 8.0;
  3082.    selectionHeightEpsilon = 8.0;
  3083.    shadingRate = 4.0;
  3084.    renderAtMediumRate = 1;
  3085.    renderAtHighRate = 2;
  3086.    renderCheckTimeSlice = 3.0;
  3087.    showSelectedShape = YES;
  3088.    drawOriginForSelectedShape = NO;
  3089.    useRendribInstead = NO;
  3090.    binaryRIB = NO;
  3091.  
  3092.    // setup 3D camera stuff
  3093.    [self setEyeAt:fromP toward:toP roll:0.0];
  3094.  
  3095.   [self setupDefaultLights];
  3096.   otherLightList = [[List alloc] init];
  3097.  
  3098.   // setup some initial global rendering state
  3099.   [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  3100.   lowRezTesselationVector[0] = lowRezTesselationVector[1] = 16.0;
  3101.   tesselationVector[0] = tesselationVector[1] = 32.0;
  3102.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  3103.  
  3104.   // stick in a reasonable shader
  3105.   theShader=[[WW3DShader alloc] init];
  3106.   [theShader setUseColor:YES];
  3107.   [theShader setColor:ribColor];
  3108.   [(N3DShader *)theShader setShader:"plastic"];
  3109.  
  3110.   // stick in a reasonable reference shape
  3111.   aShape = [[WW3DShape alloc] init];
  3112.   [aShape setShapeName:NXCopyStringBuffer("defaultTorus")];
  3113.   [aShape setShapeName:NXCopyStringBuffer("WW3DWell")];
  3114.   [aShape appendRIBCommand:[[RIBColor alloc] init]];
  3115.   //[aShape appendRIBCommand:[[RIBTorus alloc] init]];
  3116.  
  3117.   // To show off the RIBCommand archiving bug, uncomment the next
  3118.   // command, recompile, load up the WW3DPalette in IB (running IB in gdb),
  3119.   // and drag the well off the palette...
  3120.  
  3121.   [aShape appendRIBCommand:[[WW3DText alloc] initWithCharPath:"WW3DWell" 
  3122.                                    usingFont:[Font newFont:"Helvetica" 
  3123.                                        size:36] 
  3124.                                    myShape:aShape justification:NX_CENTERED]];
  3125.  
  3126.   [aShape calculateBoundingBoxStartingAt:0.0 endingAt:0.0];
  3127.  
  3128.   [aShape  setShader_:theShader];
  3129.   [[self setWorldShape:aShape] free]; // free the default world shape
  3130.   currentShape = nil;
  3131.   [self setCurrentShape:[self worldShape]];  // set current shape to be top
  3132.  
  3133.   [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
  3134.  
  3135.   theRotator = [[N3DRotator alloc] initWithCamera:self];
  3136.   [theRotator setRotationAxis:N3D_AllAxes];
  3137.  
  3138.   [self setPreTransformMatrix:(RtFloat (*)[4])N3DIdentityMatrix];
  3139.   statusBufSize = 256;
  3140.   statusBuf = (char *)NXZoneCalloc([self zone], statusBufSize, sizeof(char));
  3141.  
  3142.   fStop = RI_INFINITY;  // pinhole camera
  3143.   focalLength = 50;
  3144.   focalDistance = abs((N3D_ZComp(fromP) - N3D_ZComp(toP)));
  3145.  
  3146.   shutterOpenTime = 0.0;
  3147.   framesPerSecond = 15.0;
  3148.   frameTimeIncrement = 1.0/framesPerSecond;  // start off with 15 fps
  3149.   //savedExposureLength = exposureLength = frameTimeIncrement;  // start off with a motion blurred still camera
  3150.   savedExposureLength = exposureLength = 0.0;  // start off with a strobe still camera
  3151.   // start off with a film-like motion picture camera
  3152.   exposureLengthFactor = .5;
  3153.   
  3154.   // shot stuff
  3155.   shotStartTime = 0.0; // begin at the beginning...
  3156.   shotLength = 3.0; // let's start off with a 3 second shot
  3157.   frameNumber = 0;
  3158.   startFrame = 0;
  3159.   endFrame =  shotLength * framesPerSecond; 
  3160.  
  3161.   [self setShooting:NO];
  3162.   justFinishedShooting = NO;
  3163.   justResetExposureLength = NO;
  3164.  
  3165.   [self setupTraces];
  3166.   
  3167.     /*
  3168.      * Direct interaction support.
  3169.      */
  3170.     updateShape = NO;
  3171.     updateWhenTracking = NO;
  3172.     changeSelectedShape = NO;
  3173.  
  3174.  
  3175.   fontName = NXCopyStringBuffer("Helvetica");
  3176.   fontSize = 10.0;
  3177.   fontSpacing = 2.0;
  3178.   spacingFactor = -1.0/72.0;
  3179.   tabLength = -20 * spacingFactor;
  3180.   //timeFactor = 1.0/72.0;
  3181.   timeFactor = 3.0;
  3182.   sampleOffset = 10 * timeFactor;
  3183.  
  3184.   runTimeSystem = nil;
  3185.  
  3186.   return self;
  3187. }
  3188.  
  3189. // the receptor gets sent this message when the object is dragged into
  3190. // the File window, and when it is unarchived from the nib file.
  3191. - awake
  3192. {
  3193.   [super awake];
  3194.  
  3195.   // everything else has just been unarchived...
  3196.  
  3197.   [self initInterp];
  3198.   theRotator = [[N3DRotator alloc] initWithCamera:self];
  3199.   [theRotator setRotationAxis:N3D_AllAxes];
  3200.  
  3201.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  3202.  
  3203.   currentShape = nil;
  3204.   [self setCurrentShape:[self worldShape]];  // set current shape to be top
  3205.  
  3206.   statusBufSize = 256;
  3207.   statusBuf = (char *)NXZoneCalloc([self zone], statusBufSize, sizeof(char));
  3208.  
  3209.   frameTimeIncrement = 1.0/framesPerSecond;
  3210.   savedExposureLength = exposureLength;
  3211.   justFinishedShooting = NO;
  3212.   justResetExposureLength = NO;
  3213.  
  3214.   fontName = NXCopyStringBuffer("Helvetica");
  3215.   fontSize = 10.0;
  3216.   fontSpacing = 2.0;
  3217.   spacingFactor = -1.0/72;
  3218.   tabLength = -20 * spacingFactor;
  3219.   timeFactor = 1.0/72.0;
  3220.   sampleOffset = 10 * timeFactor;
  3221.  
  3222.   [self setupTraces];
  3223.  
  3224.   // for right now, disable binary rib output until I fix it...
  3225.   binaryRIB = NO;
  3226.  
  3227.   runTimeSystem = nil;
  3228.  
  3229.   return self;
  3230. }
  3231.  
  3232. - free
  3233.  
  3234. {
  3235.   id  theInterp;
  3236.  
  3237.  
  3238.   //NXLogError("WW3DCamera %p being free'ed\n", self);
  3239.   
  3240.   if (statusBuf) { /* NXLogError("freeing statusBuf %p\n", statusBuf);*/ NXZoneFree([self zone], statusBuf); }
  3241.   [self removeAnimateTE];
  3242.   [self removeRenderTE];
  3243.  
  3244.   if (fontName) { /* NXLogError("freeing fontName %p\n", fontName); */ free(fontName); }
  3245.  
  3246.   // MAKE SURE YOU'VE FREED EVERYTHING EXCEPT worldShape AND tclInterp BY THIS POINT!!!!!
  3247.  
  3248.   // make sure you free the tcl interp after the worldShape, because
  3249.   // EveCommands that get free'd will want to untrace their corresponding
  3250.   // tcl variables, and we don't want them sending messages to an already
  3251.   // free'd tclInterp
  3252.   // This only applies if there *is* a worldShape...
  3253.  
  3254.   if (worldShape)
  3255.   {  theInterp = tclInterp;
  3256.      //NXLogError("WW3DCamera %p being free'ed\n", self);
  3257.      [super free];
  3258.      NXLogError("about to free tclInterp %p (after super)\n", theInterp);
  3259.      [theInterp free];
  3260.   }
  3261.   else
  3262.   {  //NXLogError("about to free tclInterp %p (before super)\n", theInterp);
  3263.      [tclInterp free];
  3264.      [super free];
  3265.   }
  3266.  
  3267.   return nil;
  3268. }
  3269.  
  3270.  
  3271. - synchToSceneClock:aSceneClock
  3272. {
  3273.   float  sceneTime = [aSceneClock timestamp];
  3274.  
  3275.  
  3276.   // the idea here is to advance to the first frame that shows the scene's time.
  3277.   [self setFrameNumber:(int)(sceneTime * framesPerSecond)];
  3278.   [self display];
  3279.   return self;
  3280. }
  3281.  
  3282.  
  3283. - dumpCameraStateTo:(const char *)camName
  3284. {
  3285.   char         *valAsString, *varName;
  3286.   RtPoint      anEyePoint, aViewPoint;
  3287.   RtFloat      aRollAngle;
  3288.  
  3289.  
  3290.   valAsString = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  3291.   varName = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  3292.  
  3293.   // need to pull out my current camera parameters and send them as
  3294.   // "set camName(paramName) paramValue" to my interp here...
  3295.   // and then we need to set up write traces so that any set calls fail
  3296.  
  3297.   // 
  3298.   sprintf(varName, "%s(fieldOfView)", camName);
  3299.   sprintf(valAsString, "%f", [self fieldOfView]); // turn the value into its tcl equivalent
  3300.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3301.   //
  3302.   [self getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  3303.  
  3304.   sprintf(varName, "%s(eyePoint)", camName);
  3305.   sprintf(valAsString, "%f %f %f", N3D_XComp(anEyePoint), N3D_YComp(anEyePoint), N3D_ZComp(anEyePoint));
  3306.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3307.  
  3308.   sprintf(varName, "%s(viewPoint)", camName);
  3309.   sprintf(valAsString, "%f %f %f", N3D_XComp(aViewPoint), N3D_YComp(aViewPoint), N3D_ZComp(aViewPoint));
  3310.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3311.  
  3312.   sprintf(varName, "%s(rollAngle)", camName);
  3313.   sprintf(valAsString, "%f", aRollAngle); // turn the value into its tcl equivalent
  3314.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3315.   // 
  3316.   sprintf(varName, "%s(fStop)", camName);
  3317.   sprintf(valAsString, "%f", [self fStop]); // turn the value into its tcl equivalent
  3318.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3319.   // 
  3320.   sprintf(varName, "%s(focalLength)", camName);
  3321.   sprintf(valAsString, "%f", [self focalLength]); // turn the value into its tcl equivalent
  3322.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3323.   // 
  3324.   sprintf(varName, "%s(focalDistance)", camName);
  3325.   sprintf(valAsString, "%f", [self focalDistance]); // turn the value into its tcl equivalent
  3326.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3327.   // 
  3328.   sprintf(varName, "%s(frameNumber)", camName);
  3329.   sprintf(valAsString, "%d", [self frameNumber]); // turn the value into its tcl equivalent
  3330.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3331.   // 
  3332.   sprintf(varName, "%s(shutterOpenTime)", camName);
  3333.   sprintf(valAsString, "%f", [self shutterOpenTime]); // turn the value into its tcl equivalent
  3334.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3335.   // 
  3336.   sprintf(varName, "%s(shutterCloseTime)", camName);
  3337.   sprintf(valAsString, "%f", [self shutterCloseTime]); // turn the value into its tcl equivalent
  3338.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3339.   // 
  3340.   sprintf(varName, "%s(frameTimeIncrement)", camName);
  3341.   sprintf(valAsString, "%f", [self frameTimeIncrement]); // turn the value into its tcl equivalent
  3342.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3343.   // 
  3344.   sprintf(varName, "%s(exposureLength)", camName);
  3345.   sprintf(valAsString, "%f", [self exposureLength]); // turn the value into its tcl equivalent
  3346.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3347.   // 
  3348.  
  3349.   NXZoneFree([self zone], valAsString);
  3350.   NXZoneFree([self zone], varName);
  3351.  
  3352.   return self;
  3353. }
  3354.  
  3355.  
  3356. - restoreCameraStateFrom:(const char *)camName
  3357. {
  3358.   char         *valAsString = NULL, 
  3359.                *varName;
  3360.   RtPoint      anEyePoint, aViewPoint;
  3361.   RtFloat      aRollAngle;
  3362.  
  3363.  
  3364.   varName = (char *)NXZoneCalloc([self zone], 256, sizeof(char));
  3365.  
  3366.   // need to pull out my current camera parameters and send them as
  3367.   // "set camName(paramName) paramValue" to my interp here...
  3368.   // and then we need to set up write traces so that any set calls fail
  3369.  
  3370.   // 
  3371.   sprintf(varName, "%s(fieldOfView)", camName);
  3372.   valAsString = [tclInterp getVar:varName];
  3373.   [self setFieldOfViewByAngle:(float)atof(valAsString)];
  3374.   // should I free valAsString here?
  3375.  
  3376.   //
  3377.   [self getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  3378.  
  3379.   sprintf(varName, "%s(eyePoint)", camName);
  3380.   sprintf(valAsString, "%f %f %f", N3D_XComp(anEyePoint), N3D_YComp(anEyePoint), N3D_ZComp(anEyePoint));
  3381.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3382.  
  3383.   sprintf(varName, "%s(viewPoint)", camName);
  3384.   sprintf(valAsString, "%f %f %f", N3D_XComp(aViewPoint), N3D_YComp(aViewPoint), N3D_ZComp(aViewPoint));
  3385.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3386.  
  3387.   sprintf(varName, "%s(rollAngle)", camName);
  3388.   sprintf(valAsString, "%f", aRollAngle); // turn the value into its tcl equivalent
  3389.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3390.   // 
  3391.   sprintf(varName, "%s(fStop)", camName);
  3392.   sprintf(valAsString, "%f", [self fStop]); // turn the value into its tcl equivalent
  3393.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3394.   // 
  3395.   sprintf(varName, "%s(focalLength)", camName);
  3396.   sprintf(valAsString, "%f", [self focalLength]); // turn the value into its tcl equivalent
  3397.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3398.   // 
  3399.   sprintf(varName, "%s(focalDistance)", camName);
  3400.   sprintf(valAsString, "%f", [self focalDistance]); // turn the value into its tcl equivalent
  3401.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3402.   // 
  3403.   sprintf(varName, "%s(frameNumber)", camName);
  3404.   sprintf(valAsString, "%d", [self frameNumber]); // turn the value into its tcl equivalent
  3405.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3406.   // 
  3407.   sprintf(varName, "%s(shutterOpenTime)", camName);
  3408.   sprintf(valAsString, "%f", [self shutterOpenTime]); // turn the value into its tcl equivalent
  3409.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3410.   // 
  3411.   sprintf(varName, "%s(shutterCloseTime)", camName);
  3412.   sprintf(valAsString, "%f", [self shutterCloseTime]); // turn the value into its tcl equivalent
  3413.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3414.   // 
  3415.   sprintf(varName, "%s(frameTimeIncrement)", camName);
  3416.   sprintf(valAsString, "%f", [self frameTimeIncrement]); // turn the value into its tcl equivalent
  3417.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3418.   // 
  3419.   sprintf(varName, "%s(exposureLength)", camName);
  3420.   sprintf(valAsString, "%f", [self exposureLength]); // turn the value into its tcl equivalent
  3421.   [tclInterp setVar:varName toReadOnlyValue:valAsString];
  3422.   // 
  3423.  
  3424.   NXZoneFree([self zone], valAsString);
  3425.   NXZoneFree([self zone], varName);
  3426.  
  3427.   return self;
  3428. }
  3429.  
  3430.  
  3431. - evaluateCameraInterpolationRoutineWith:(float)u
  3432. {
  3433.    char   cmd[80];
  3434.  
  3435.  
  3436.    sprintf(cmd, "eval $cam(interpolationProc) %f", u);
  3437.    //NXLogError("WW3DCamera's interp evaluating camera interpolation routine with %f for frame number %d here...\n", 
  3438.    //          u, [self frameNumber]);
  3439.    [tclInterp globalEval:cmd];
  3440.    return self;
  3441. }
  3442.  
  3443. - renderMapsToStream:(NXStream *)ns
  3444. {
  3445.   [worldShape renderMaps:self usingStream:ns];
  3446.   return self;
  3447. }
  3448.  
  3449. - renderMaps
  3450. {
  3451.   [worldShape renderMaps:self];
  3452.   return self;
  3453. }
  3454.  
  3455. - worldBegin:(RtToken)context 
  3456.    RtInt        jitterFlag = 1; 
  3457.    float        u;
  3458.    int          theFrameNumber;
  3459.    static char  *offPtr = "off";
  3460.    static int   patchMaxLevel = 4.0;
  3461.  
  3462.  
  3463.    if (dumpingToRIB)
  3464.    {  //static RtInt v31 = 301; 
  3465.       //RiOption(RI_ARCHIVE, "outputversion", &v31, RI_NULL);
  3466.  
  3467.       [self renderMaps];
  3468.    }
  3469.    if (useRendribInstead)
  3470.    {  RiArchiveRecord(RI_COMMENT, "the following declare all the non-standard variables for rendrib");
  3471.       RiArchiveRecord(RI_COMMENT, "rendrib declares these internally, but prman or WavesWorld would complain if");
  3472.       RiArchiveRecord(RI_COMMENT, "it got passed a RIB file with these attributes if they hadn't been declared");
  3473.       RiDeclare("include", "uniform string");
  3474.       RiDeclare("shadows", "uniform string");
  3475.       RiDeclare("verbosity", "uniform string");
  3476.       RiDeclare("casts_shadows", "uniform string");
  3477.       RiDeclare("zonal", "uniform string");
  3478.       RiDeclare("patchsize", "uniform float");
  3479.       RiDeclare("elemsize", "uniform float");
  3480.       RiDeclare("minsize", "uniform float");
  3481.       RiDeclare("displacement", "uniform float");
  3482.       RiDeclare("patch_maxlevel", "uniform integer");
  3483.       RiDeclare("max_raylevel", "uniform integer");
  3484.       RiDeclare("minshadowbias", "uniform float");
  3485.       RiDeclare("minsamples", "uniform integer");
  3486.       RiDeclare("maxsamples", "uniform integer");
  3487.       RiDeclare("branch_ratio", "uniform integer");
  3488.       RiDeclare("max_branch_ratio", "uniform integer");
  3489.       RiDeclare("binary", "uniform integer");
  3490.       RiDeclare("averagecolor", "uniform color");
  3491.       RiDeclare("emissioncolor", "uniform color");      
  3492.       RiArchiveRecord(RI_COMMENT, "the following turns off shadows as the default for this file when using rendrib");
  3493.       RiAttribute("light", "shadows", &offPtr, RI_NULL);
  3494.    }
  3495.    else
  3496.    {  RiArchiveRecord(RI_COMMENT, "a shader included in prman 3.4 used to ensure color doesn't exceed alpha");
  3497.       RiImager("clamptoalpha", RI_NULL);
  3498.    } 
  3499.  
  3500.    // okay, if the shading rate is less than 1, use PixelSamples 3 3 
  3501.    // okay, if the shading rate is greater than or equal to 1 but less than 4, use PixelSamples 2 2 
  3502.    // okay, if the shading rate is greater than or equal to 4, use PixelSamples 1 1 
  3503.    if ((shadingRate < 1.0) && (exposureLength > 0.0))
  3504.    {  if (useRendribInstead)
  3505.       {  RiArchiveRecord(RI_COMMENT, "the following stops patch subdivision at level 8 when using rendrib.  If your geometry looks blocky, make the value bigger");
  3506.          patchMaxLevel = 8;
  3507.          RiAttribute("render", "patch_maxlevel", &patchMaxLevel, RI_NULL);
  3508.          RiArchiveRecord(RI_COMMENT, "please note: I'm purposely setting the PixelSamples to 3 3 because you're using such a high quality shading rate");
  3509.          RiArchiveRecord(RI_COMMENT, "and there is potentially motion blur in this frame.");
  3510.          RiArchiveRecord(RI_COMMENT, 
  3511.              "Since you're probably using rendrib, though, the ShadingRate is ignored, but things will render faster if the PixelSamples was lower.");
  3512.       }
  3513.       else
  3514.       {  RiArchiveRecord(RI_COMMENT, 
  3515.              "please note: I'm purposely setting the PixelSamples to 3 3 because you're using such a high quality shading rate.");
  3516.      RiArchiveRecord(RI_COMMENT, 
  3517.              "Assuming you're using prman, things will render faster if this number was lower, or the ShadingRate value was higher.");
  3518.       }
  3519.       RiPixelSamples(3.0, 3.0);
  3520.    }
  3521.    else
  3522.    {  if (shadingRate < 4.0)
  3523.       {  if (useRendribInstead)
  3524.          {  RiArchiveRecord(RI_COMMENT, "the following stops patch subdivision at level 4 when using rendrib.  If your geometry looks blocky, make the value bigger");
  3525.             patchMaxLevel = 4;
  3526.             RiAttribute("render", "patch_maxlevel", &patchMaxLevel, RI_NULL);
  3527.             RiArchiveRecord(RI_COMMENT, 
  3528.                 "please note: I'm purposely setting the PixelSamples to 2 2 because you're using a reasonable quality shading rate.");
  3529.         RiArchiveRecord(RI_COMMENT, 
  3530.                 "Since you're probably using rendrib, though, the ShadingRate is ignored, but things will render faster if the PixelSamples was lower.");
  3531.      }
  3532.          else
  3533.          {  RiArchiveRecord(RI_COMMENT, 
  3534.                 "please note: I'm purposely setting the PixelSamples to 2 2 because you're using  a reasonable quality shading rate.");
  3535.         RiArchiveRecord(RI_COMMENT, 
  3536.                 "Assuming you're using prman, things will render faster if this number was lower, or the ShadingRate value was higher.");
  3537.       }
  3538.      RiPixelSamples(2.0, 2.0);
  3539.       }
  3540.       else
  3541.       {  if (useRendribInstead)
  3542.          {  RiArchiveRecord(RI_COMMENT, "the following stops patch subdivision at level 2 when using rendrib.  If your geometry looks blocky, make the value bigger");
  3543.             patchMaxLevel = 2;
  3544.             RiAttribute("render", "patch_maxlevel", &patchMaxLevel, RI_NULL);
  3545.             RiArchiveRecord(RI_COMMENT, 
  3546.                 "please note: I'm purposely setting the PixelSamples to 1 1 because you're using a low quality shading rate.");
  3547.         RiArchiveRecord(RI_COMMENT, 
  3548.                 "Since you're probably using rendrib, though, the ShadingRate is ignored, but things will look better if the PixelSamples was higher.");
  3549.      }
  3550.          else
  3551.          {  RiArchiveRecord(RI_COMMENT, 
  3552.                 "please note: I'm purposely setting the PixelSamples to 1 1 because you're using  a low quality shading rate.");
  3553.         RiArchiveRecord(RI_COMMENT, 
  3554.                 "Assuming you're using prman, things will look better if this number was higher, or the ShadingRate value was lower.");
  3555.       }
  3556.      RiPixelSamples(1.0, 1.0);
  3557.       }
  3558.    }
  3559.  
  3560.  
  3561.    // Run camera interpolation procedure here. We do it here (as opposed
  3562.    // to doing it in drawSelf:), because at this point, all the camera
  3563.    // parameters are as fixed as they're gonna get for this frame.
  3564.  
  3565.    // when a new frame number is set with setFrameNumber:, it sets the 
  3566.    // BOOL evaluateInterpProc.  We only want to run this proc once per
  3567.    // frame, but we also don't want to do it until this point.  So...
  3568.    // at this point, if the flag is set, we evaluate the proc with
  3569.    // the current value of u.
  3570.    // note that if the currentFrame == startFrame, and the flag is set,
  3571.    // we need to do some initial work to set up the state.  We need to
  3572.    // fill out the global tcl array startCam(), which is to have the state 
  3573.    // of the current camera in read-only variables...
  3574.  
  3575.    if (shooting)
  3576.    {  theFrameNumber = [self frameNumber];
  3577.  
  3578.       if (theFrameNumber == 0) // sanity check!
  3579.       {  savedExposureLength = exposureLength; 
  3580.          [self setExposureLength:([self frameTimeIncrement] * exposureLengthFactor)];
  3581.       }
  3582.       if (evaluateInterpProc)
  3583.       {  if (theFrameNumber == 0) 
  3584.          {  // initialize startCam() array with my current state 
  3585.             [tclInterp unsetVar:"startCam"];
  3586.             [self dumpCameraStateTo:"startCam"];  
  3587.             u = 0;
  3588.          } 
  3589.          else
  3590.          {  // calculate u, where u is 0 at startFrame and 1 at endFrame
  3591.             // let's say startFrame is 0, endFrame is 100, and frameNumber is 25
  3592.             // we want u to be .25
  3593.             // note that we should not have to worry about div by zero here...
  3594.             u = (float)theFrameNumber/(float)([self endFrame] - 1);
  3595.          }
  3596.          [self evaluateCameraInterpolationRoutineWith:u];
  3597.          evaluateInterpProc = NO;
  3598.       }
  3599.    }
  3600.    else  // if we're not shooting, we want the camera to be in synch with the scene clock and be a strobe camera...
  3601.    {  // ask the sceneClock what time it is, and make ourselves a strobe camera
  3602.       if (justFinishedShooting) // when we come out of a shot, reset the exposureLength to what it was previously
  3603.       {  [self setExposureLength:savedExposureLength]; // need to do it "correctly", so tcl is notified
  3604.          justFinishedShooting = NO;
  3605.       }
  3606.       [self setShutterOpenTime:[sceneClock timestamp]];  // need to do it "correctly", so tcl is notified
  3607.    }
  3608.  
  3609.    // If I want to support depth-of-field, need to call RiDepthOfField()
  3610.    RiDepthOfField(fStop, focalLength, focalDistance);
  3611.    // If I want to support motion blur, need to call RiShutter(), as well 
  3612.    // as having  RiMotionBegin/End blocks around primitives
  3613.    if (shooting)
  3614.    {  RiShutter(shutterOpenTime, (shutterOpenTime + (exposureLength * exposureLengthFactor)));
  3615.    }
  3616.    else
  3617.    {  RiShutter(shutterOpenTime, (shutterOpenTime + exposureLength));
  3618.    }
  3619.    if (exposureLength > 0.0)  // is it a strobe or not?
  3620.    {  // optimize for motion blur...
  3621.       // really should find out what the hider has been set to...
  3622.       RiHider("hidden", "jitter", &jitterFlag, RI_NULL);
  3623.    }
  3624.  
  3625.    // or whatever the heck is the right thang...
  3626.    if (renderCount == renderAtMediumRate)
  3627.    {  RiShadingRate(50.0);
  3628.    } 
  3629.    else
  3630.    {  if (renderCount == renderAtHighRate)
  3631.       {  RiShadingRate(5.0);
  3632.       }
  3633.    }
  3634.  
  3635.    [super worldBegin:context];
  3636.    return self;
  3637. }
  3638.  
  3639. - getTransformMatrix:(RtMatrix)aMatrix
  3640. {
  3641.   N3D_CopyMatrix(transform, aMatrix);
  3642.   return self;
  3643. }
  3644.  
  3645. - takeStatusText:sender  { statusText = sender; return self; }
  3646.  
  3647. - delegate { return delegate; }
  3648.  
  3649. /////////////////////// 
  3650. // 3D stuff
  3651. /////////////////////// 
  3652. - setNoCurrentShape:sender { currentShape = nil; return self; }
  3653.  
  3654. - currentShape { return currentShape; }
  3655. - setCurrentShape:newCurrentShape
  3656. {
  3657.   // should make sure newShape is a child of worldShape...
  3658.   [currentShape setSelected:NO andDrawOrigin:NO];
  3659.  
  3660.   [worldShape setDrawAsBox:drawWorldAsBox];
  3661.  
  3662.   if (drawCurrentAsBox)
  3663.   {  [currentShape setDrawAsBox:NO];
  3664.   }
  3665.  
  3666.   currentShape = newCurrentShape;
  3667.   [currentShape setSelected:showSelectedShape andDrawOrigin:drawOriginForSelectedShape];
  3668.   if (drawCurrentAsBox)
  3669.   {  [currentShape setDrawAsBox:YES];
  3670.   }
  3671.   
  3672.   // WAVE this is expensive; I should have a flag...
  3673.   //[self display];
  3674.  
  3675.   if (statusText) // potentially record activity
  3676.   {  sprintf(statusBuf, "currentShape is: %s", [currentShape shapeName]);
  3677.      [statusText setStringValue:statusBuf];
  3678.   }
  3679.  
  3680.   return self;
  3681. }
  3682.  
  3683. - (RtFloat)tesselation { return tesselationVector[0]; }
  3684.  
  3685. - setTesselation:(RtFloat)newValue 
  3686.   tesselationVector[0] = tesselationVector[1] = newValue;
  3687.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  3688.  
  3689.   return self;
  3690. }
  3691.  
  3692. - takeTesselation:sender
  3693. {
  3694.   tesselationVector[0] = tesselationVector[1] = [sender floatValue];
  3695.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  3696.  
  3697.   if (statusText) // potentially record activity
  3698.   {  sprintf(statusBuf, "tesselation set to (%f %f)", 
  3699.          tesselationVector[0], tesselationVector[1]);
  3700.      [statusText setStringValue:statusBuf];
  3701.   }
  3702.  
  3703.   [self display];
  3704.  
  3705.   return self;
  3706. }
  3707.  
  3708. - (RtFloat)lowRezTesselation { return lowRezTesselationVector[0]; }
  3709.  
  3710. - setLowRezTesselation:(RtFloat)newValue 
  3711.   lowRezTesselationVector[0] = lowRezTesselationVector[1] = newValue;
  3712.  
  3713.   return self;
  3714. }
  3715.  
  3716. - takeLowRezTesselation:sender
  3717. {
  3718.   lowRezTesselationVector[0] = lowRezTesselationVector[1] = [sender floatValue];
  3719.   if (statusText) // potentially record activity
  3720.   {  sprintf(statusBuf, "low rez tesselation set to (%f %f)", 
  3721.          lowRezTesselationVector[0], lowRezTesselationVector[1]);
  3722.      [statusText setStringValue:statusBuf];
  3723.   }
  3724.   return self;
  3725. }
  3726.  
  3727. - (float)shadingRate { return shadingRate; }
  3728. - takeShadingRate:sender
  3729. {
  3730.   shadingRate = [sender floatValue];
  3731.   if (shadingRate < 0.25)
  3732.   {  shadingRate = 0.25;
  3733.   }
  3734.   if (shadingRate > 100.0)
  3735.   {  shadingRate = 100.0;
  3736.   }
  3737.   return self;
  3738. }
  3739.  
  3740. - takeAmbientLightState:sender
  3741. {
  3742.    [ambientLight switchLight:[sender intValue]];
  3743.    return [self display];
  3744. }
  3745. - takeAmbientLightIntensity:sender
  3746. {
  3747.    [ambientLight setIntensity:[sender floatValue]];
  3748.    return [self display];
  3749. }
  3750. - takeAmbientLightColor:sender
  3751. {
  3752.    [ambientLight setColor:[sender color]];
  3753.    return [self display];
  3754. }
  3755. - takeLeftLightState:sender
  3756. {
  3757.    [leftLight switchLight:[sender intValue]];
  3758.    return [self display];
  3759. }
  3760. - takeLeftLightIntensity:sender
  3761. {
  3762.    [leftLight setIntensity:[sender floatValue]];
  3763.    return [self display];
  3764. }
  3765. - takeLeftLightColor:sender
  3766. {
  3767.    [leftLight setColor:[sender color]];
  3768.    return [self display];
  3769. }
  3770. - takeRightLightState:sender
  3771. {
  3772.    [rightLight switchLight:[sender intValue]];
  3773.    return [self display];
  3774. }
  3775. - takeRightLightIntensity:sender
  3776. {
  3777.    [rightLight setIntensity:[sender floatValue]];
  3778.    return [self display];
  3779. }
  3780. - takeRightLightColor:sender
  3781. {
  3782.    [rightLight setColor:[sender color]];
  3783.    return [self display];
  3784. }
  3785.  
  3786. - (BOOL)ambientLightState { return [ambientLight on]; }
  3787. - (RtFloat)ambientLightIntensity { return [ambientLight intensity]; }
  3788. - (NXColor)ambientLightColor { return [ambientLight color]; }
  3789.  
  3790. - (BOOL)leftLightState { return [leftLight on]; }
  3791. - (RtFloat)leftLightIntensity { return [leftLight intensity]; }
  3792. - (NXColor)leftLightColor { return [leftLight color]; }
  3793.  
  3794. - (BOOL)rightLightState { return [rightLight on]; }
  3795. - (RtFloat)rightLightIntensity { return [ rightLight intensity]; }
  3796. - (NXColor)rightLightColor { return [rightLight color]; }
  3797.  
  3798. - saveImage:sender
  3799. {
  3800.   static id savePanel=nil;
  3801.   NXStream *ts;
  3802.  
  3803.  
  3804.   if (!savePanel) 
  3805.   {  savePanel=[SavePanel new];
  3806.   }
  3807.  
  3808.   [savePanel setRequiredFileType:"tiff"];
  3809.   if([savePanel runModal])
  3810.   {  ts = NXOpenMemory(NULL, 0, NX_READWRITE);
  3811.      [image writeTIFF:ts allRepresentations:NO usingCompression:NX_TIFF_COMPRESSION_LZW andFactor:1.0];
  3812.      NXSaveToFile(ts, [savePanel filename]);
  3813.      NXCloseMemory(ts,NX_FREEBUFFER);
  3814.   }
  3815.  
  3816.   return self;
  3817. }
  3818.  
  3819.  
  3820. - dumpRIB:sender
  3821. {
  3822.   static id savePanel=nil;
  3823.   NXStream *ts;
  3824.   char filename[MAXPATHLEN+1];
  3825.   char *ascii = "ascii",
  3826.        *binary = "binary";
  3827.  
  3828.  
  3829.   dumpingToRIB = YES;
  3830.  
  3831.   if (statusText) // potentially record activity
  3832.   {  sprintf(statusBuf, "dumping RIB...");
  3833.      [statusText setStringValue:statusBuf];
  3834.   }
  3835.  
  3836.   if (!savePanel) 
  3837.   {  savePanel=[SavePanel new];
  3838.   }
  3839.   [savePanel setRequiredFileType:"rib"];
  3840.  
  3841.   if([savePanel runModal])
  3842.   {  // returned w/pathname, open a stream and
  3843.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3844.  
  3845.      // remove the .rib extension from the path returned by the SavePanel
  3846.      basename([savePanel filename], ".rib", filename);
  3847.  
  3848.      // feed to NXPrintf to put in the custom Display command
  3849.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  3850.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  3851.      NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", filename);
  3852.      NXPrintf(ts, "ShadingRate %f\n", shadingRate);
  3853.  
  3854.      // set the output format:
  3855.      if (binaryRIB)
  3856.      {  format = binary;
  3857.      }
  3858.      else
  3859.      {  format = ascii;
  3860.      }
  3861.      RiDeclare("format", "uniform string");
  3862.      RiOption("rib", "format", &format, RI_NULL);
  3863.  
  3864.      // then feed the rib code to the stream and
  3865.      [self copyRIBCode:ts];
  3866.      // save the stream to the file selected in the savepanel
  3867.      NXSaveToFile(ts, [savePanel filename]);
  3868.  
  3869.      // and close the stream (which also flushes it), also making sure
  3870.      // that the allocated memory is freed.
  3871.     NXCloseMemory(ts,NX_FREEBUFFER);
  3872.   }
  3873.  
  3874.   if (statusText) // potentially record activity
  3875.   {  sprintf(statusBuf, "done!");
  3876.      [statusText setStringValue:statusBuf];
  3877.   }
  3878.   dumpingToRIB = NO;
  3879.   return self;
  3880. }
  3881.  
  3882. - setRunTimeSystem:newRTS
  3883. {
  3884.    runTimeSystem = newRTS;
  3885.    return self;
  3886. }
  3887.  
  3888.  
  3889. - copyRIBCode:(NXStream *)ts
  3890. {
  3891.   id retID, tmpText = statusText;
  3892.  
  3893.  
  3894.   sprintf(statusBuf, "disabling status display to avoid NeXT's copyRIBCode: bug...");
  3895.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  3896.   statusText = nil;
  3897.   [runTimeSystem disableStatusText];
  3898.   [self renderMapsToStream:ts];
  3899.  
  3900.   retID = [super copyRIBCode:ts];
  3901.   statusText = tmpText;
  3902.   [runTimeSystem reenableStatusText];
  3903.   return retID;
  3904. }
  3905.  
  3906.  
  3907. - dumpShotToRIBFile:(const char *)longFilename
  3908. {
  3909.   NXStream   *ts;
  3910.   char       filename[MAXPATHLEN+1];
  3911.   int        oldFrameNumber, i, startI, endI, incI;
  3912.   static id  savePanel=nil;
  3913.  
  3914.  
  3915.   if (statusText) // potentially record activity
  3916.   {  sprintf(statusBuf, "dumping complete shot to RIB file %s...", longFilename);
  3917.      [statusText setStringValue:statusBuf];
  3918.   }
  3919.  
  3920.   // make sure it's a RIB file (at least 1.rib)...
  3921.   if (longFilename && (strlen(longFilename) > 4) && (!strcmp(".rib", (const char *)(longFilename + strlen(longFilename) - 4))))
  3922.   {  // returned w/pathname, open a stream and
  3923.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  3924.  
  3925.      // remove the .rib extension from the path returned by the SavePanel
  3926.      basename(longFilename, ".rib", filename);
  3927.  
  3928.      // feed to NXPrintf to put in the custom Display command
  3929.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  3930.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  3931.  
  3932.  
  3933.      // we need to loop over the whole shot, starting at the first frame, and incrementing correctly.
  3934.      // The 3DKit will take care of putting in frame numbers, but we need to manage the names of the 
  3935.      // tiff files that will get saved out. The WWAnimatable and WWRenderable objects that this camera
  3936.      // is attached to will take care of figuring out what time it is when the camera takes their picture.
  3937.  
  3938.      NXPrintf(ts, "ShadingRate %f\n\n\n", shadingRate);
  3939.      
  3940.      oldFrameNumber = [self frameNumber];
  3941.      startI = [self startFrame];
  3942.      endI = [self endFrame];
  3943.      incI = [self frameIncrement];
  3944.  
  3945.      // due to a bug in NeXT's 3DKit, we want to make sure that
  3946.      // nothing gets written out to a view while we're in
  3947.      // "copyRIBCode:". Unfortunately, that's pretty hard...  The most likely
  3948.      // culprit is a routine (like the current camera's interpolation routine)
  3949.      // writing out to the "statusText" outlet.  Probably the best thing to do
  3950.      // then is to save the value of that outlet and set it to nil for the
  3951.      // duration of copyRIBCode:...  actually, the better thing to do is
  3952.      // probably reimplement copyRIBCode:, where I unset the outlet, call
  3953.      // the super's version, and then set it back.  Yea, let's try that...
  3954.  
  3955.      shooting = YES;
  3956.      [self setFrameNumber:(startI - 1)]; // just to flush state...
  3957.      for (i = startI; i < endI; i += incI)
  3958.      {  [self setFrameNumber:i]; 
  3959.         NXPrintf(ts, "\n\n");
  3960.         NXPrintf(ts, "\nDisplay \"%s.%d.tiff\" \"file\" \"rgba\"\n", filename, i);
  3961.         [self copyRIBCode:ts];
  3962.      }
  3963.      NXSaveToFile(ts, [savePanel filename]);
  3964.      NXCloseMemory(ts,NX_FREEBUFFER);
  3965.  
  3966.      [self setFrameNumber:oldFrameNumber];
  3967.      shooting = NO;
  3968.   }
  3969.   else
  3970.   {  sprintf(statusBuf, "<%s> is not a valid filename for a RIB file.\n", longFilename);
  3971.      [statusText setStringValue:statusBuf];
  3972.      return nil;
  3973.   }
  3974.   if (statusText) // potentially record activity
  3975.   {  sprintf(statusBuf, "done!");
  3976.      [statusText setStringValue:statusBuf];
  3977.   }
  3978.   return self;
  3979. }
  3980.  
  3981.  
  3982. - dumpShotToRIB:sender
  3983. {
  3984.   static id  savePanel=nil;
  3985.   NXStream   *ts;
  3986.   char       filename[MAXPATHLEN+1];
  3987.   int        oldFrameNumber, i, startI, endI, incI;
  3988.   char *ascii = "ascii",
  3989.        *binary = "binary"; 
  3990.  
  3991.  
  3992.   if (statusText) // potentially record activity
  3993.   {  sprintf(statusBuf, "dumping complete shot to RIB...");
  3994.      [statusText setStringValue:statusBuf];
  3995.   }
  3996.  
  3997.   if (!savePanel) 
  3998.   {  savePanel=[SavePanel new];
  3999.   }
  4000.   [savePanel setRequiredFileType:"rib"];
  4001.  
  4002.   if([savePanel runModal])
  4003.   {  // returned w/pathname, open a stream and
  4004.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  4005.  
  4006.      // remove the .rib extension from the path returned by the SavePanel
  4007.      basename([savePanel filename], ".rib", filename);
  4008.  
  4009.      // set the output format:
  4010.      if (binaryRIB)
  4011.      {  format = binary;
  4012.      }
  4013.      else
  4014.      {  format = ascii;
  4015.      }
  4016.      RiDeclare("format", "uniform string");
  4017.      RiOption("rib", "format", &format, RI_NULL);
  4018.  
  4019.      // feed to NXPrintf to put in the custom Display command
  4020.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  4021.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  4022.  
  4023.  
  4024.      // we need to loop over the whole shot, starting at the first frame, and incrementing correctly.
  4025.      // The 3DKit will take care of putting in frame numbers, but we need to manage the names of the 
  4026.      // tiff files that will get saved out. The WWAnimatable and WWRenderable objects that this camera
  4027.      // is attached to will take care of figuring out what time it is when the camera takes their picture.
  4028.  
  4029.      NXPrintf(ts, "ShadingRate %f\n", shadingRate);
  4030.      
  4031.      oldFrameNumber = [self frameNumber];
  4032.      startI = [self startFrame];
  4033.      endI = [self endFrame];
  4034.      incI = [self frameIncrement];
  4035.  
  4036.      // due to a bug in NeXT's 3DKit, we want to make sure that
  4037.      // nothing gets written out to a view while we're in
  4038.      // "copyRIBCode:". Unfortunately, that's pretty hard...  The most likely
  4039.      // culprit is a routine (like the current camera's interpolation routine)
  4040.      // writing out to the "statusText" outlet.  Probably the best thing to do
  4041.      // then is to save the value of that outlet and set it to nil for the
  4042.      // duration of copyRIBCode:...  actually, the better thing to do is
  4043.      // probably reimplement copyRIBCode:, where I unset the outlet, call
  4044.      // the super's version, and then set it back.  Yea, let's try that...
  4045.  
  4046.      shooting = YES;
  4047.      [self setFrameNumber:(startI - 1)]; // just to flush state...
  4048.       // set scene time as we're moving through...
  4049.       [sceneClock setCurrentTimeQuietly:[self shutterOpenTime]];   // god this is gross!!
  4050.       [sceneClock setCurrentTimeQuietly:[self shutterCloseTime]];  // god this is gross!!
  4051.  
  4052.      for (i = startI; i < endI; i += incI)
  4053.      {  [self setFrameNumber:i]; 
  4054.         // set scene time as we're moving through...
  4055.         [sceneClock setCurrentTimeQuietly:[self shutterOpenTime]];   // god this is gross!!
  4056.         [sceneClock setCurrentTimeQuietly:[self shutterCloseTime]];  // god this is gross!!
  4057.         NXPrintf(ts, "Display \"%s.%d.tiff\" \"file\" \"rgba\"\n", filename, i);
  4058.         [self copyRIBCode:ts];
  4059.      }
  4060.      NXSaveToFile(ts, [savePanel filename]);
  4061.      NXCloseMemory(ts,NX_FREEBUFFER);
  4062.  
  4063.      [self setFrameNumber:oldFrameNumber];
  4064.      [sceneClock setCurrentTime:[self shutterOpenTime]];   // god this is gross!!
  4065.      shooting = NO;
  4066.   }
  4067.  
  4068.   if (statusText) // potentially record activity
  4069.   {  sprintf(statusBuf, "done!");
  4070.      [statusText setStringValue:statusBuf];
  4071.   }
  4072.   return self;
  4073. }
  4074.  
  4075.  
  4076. - dumpEve:sender
  4077. {
  4078.   static id savePanel=nil;
  4079.   NXStream *ts;
  4080.  
  4081.  
  4082.   if (statusText) // potentially record activity
  4083.   {  sprintf(statusBuf, "dumping Eve...");
  4084.      [statusText setStringValue:statusBuf];
  4085.   }
  4086.  
  4087.   if (!savePanel) 
  4088.   {  savePanel=[SavePanel new];
  4089.   }
  4090.   [savePanel setRequiredFileType:"eve"];
  4091.  
  4092.   if([savePanel runModal])
  4093.   {  // returned w/pathname, open a stream and
  4094.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  4095.  
  4096.      // feed to NXPrintf to put in the custom Display command
  4097.      NXPrintf(ts, "# This eve model file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  4098.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  4099.  
  4100.      [[worldShape tclInterp] writeState:ts];
  4101.  
  4102.      // then tell the worldShape to write itself out, which will recurse down...
  4103.      [worldShape writeEve:ts atTabLevel:0];
  4104.  
  4105.      // save the stream to the file selected in the savepanel
  4106.      NXSaveToFile(ts, [savePanel filename]);
  4107.  
  4108.      // and close the stream (which also flushes it), also making sure
  4109.      // that the allocated memory is freed.
  4110.     NXCloseMemory(ts,NX_FREEBUFFER);
  4111.   }
  4112.  
  4113.   if (statusText) // potentially record activity
  4114.   {  sprintf(statusBuf, "done!");
  4115.      [statusText setStringValue:statusBuf];
  4116.   }
  4117.   return self;
  4118. }
  4119.  
  4120.  
  4121. - dumpScene:sender
  4122. {
  4123.   static id savePanel=nil;
  4124.   NXStream *ts;
  4125.  
  4126.  
  4127.   if (statusText) // potentially record activity
  4128.   {  sprintf(statusBuf, "dumping scene...");
  4129.      [statusText setStringValue:statusBuf];
  4130.   }
  4131.  
  4132.   if (!savePanel) 
  4133.   {  savePanel=[SavePanel new];
  4134.   }
  4135.   [savePanel setRequiredFileType:"wwScene"];
  4136.  
  4137.   if([savePanel runModal])
  4138.   {  // returned w/pathname, open a stream and
  4139.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  4140.  
  4141.      NXPrintf(ts, "#\n");
  4142.      NXPrintf(ts, "# This eve scene file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  4143.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  4144.  
  4145.      [[worldShape tclInterp] writeState:ts];
  4146.  
  4147.      // then tell the worldShape to write itself out, which will recurse down...
  4148.      [worldShape writeScene:ts atTabLevel:0];
  4149.  
  4150.      // save the stream to the file selected in the savepanel
  4151.      NXSaveToFile(ts, [savePanel filename]);
  4152.  
  4153.      // and close the stream (which also flushes it), also making sure
  4154.      // that the allocated memory is freed.
  4155.     NXCloseMemory(ts,NX_FREEBUFFER);
  4156.   }
  4157.  
  4158.   if (statusText) // potentially record activity
  4159.   {  sprintf(statusBuf, "done!");
  4160.      [statusText setStringValue:statusBuf];
  4161.   }
  4162.   return self;
  4163. }
  4164.  
  4165. - dumpInventor:sender
  4166. {
  4167.   static id savePanel=nil;
  4168.   NXStream *ts;
  4169.  
  4170.  
  4171.   if (statusText) // potentially record activity
  4172.   {  sprintf(statusBuf, "dumping SGI Open Inventor 2.0 file...");
  4173.      [statusText setStringValue:statusBuf];
  4174.   }
  4175.  
  4176.   if (!savePanel) 
  4177.   {  savePanel=[SavePanel new];
  4178.   }
  4179.   [savePanel setRequiredFileType:"iv"];
  4180.  
  4181.   if([savePanel runModal])
  4182.   {  // returned w/pathname, open a stream and
  4183.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  4184.  
  4185.      NXPrintf(ts, "#Inventor V2.0 ascii\n#\n");
  4186.      NXPrintf(ts, "# This Inventor file was automatically generated from an eve model file\n");
  4187.      NXPrintf(ts, "# generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  4188.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  4189.      NXPrintf(ts, "# At the tone, the  current time is: %f ... Beep!\n#\n#\n", shutterOpenTime);
  4190.  
  4191.      NXPrintf(ts, "Separator {\n");
  4192.      NXPrintf(ts, "\t# RenderMan is a left-handed coordinate system, Inventor is right-handed, so this should fix things, right?\n");
  4193.      NXPrintf(ts, "\tScale {\n");
  4194.      NXPrintf(ts, "\t\tscaleFactor 1 1 -1\n");
  4195.      NXPrintf(ts, "\t}\n");
  4196.  
  4197.      // then tell the worldShape to write itself out, which will recurse down...
  4198.      [worldShape writeInventorAtTime:shutterOpenTime to:ts atTabLevel:1];
  4199.  
  4200.      NXPrintf(ts, "}\n");
  4201.  
  4202.      // save the stream to the file selected in the savepanel
  4203.      NXSaveToFile(ts, [savePanel filename]);
  4204.  
  4205.      // and close the stream (which also flushes it), also making sure
  4206.      // that the allocated memory is freed.
  4207.     NXCloseMemory(ts,NX_FREEBUFFER);
  4208.   }
  4209.  
  4210.   if (statusText) // potentially record activity
  4211.   {  sprintf(statusBuf, "done!");
  4212.      [statusText setStringValue:statusBuf];
  4213.   }
  4214.   return self;
  4215. }
  4216.  
  4217.  
  4218. - (const char *)fontName { return fontName; }
  4219. - (float)fontSize { return fontSize; }
  4220. - (float)fontSpacing { return fontSpacing; }
  4221. - (float)spacingFactor { return spacingFactor; }
  4222. - (float)tabLength { return tabLength; }
  4223. - (float)timeFactor { return timeFactor; }
  4224. - (float)sampleOffset { return sampleOffset; }
  4225.  
  4226. - dump3DTextScene:sender
  4227. {
  4228.   static id savePanel=nil;
  4229.   NXStream *ts;
  4230.  
  4231.  
  4232.   if (statusText) // potentially record activity
  4233.   {  sprintf(statusBuf, "dumping 3D Text scene...");
  4234.      [statusText setStringValue:statusBuf];
  4235.   }
  4236.  
  4237.   if (!savePanel) 
  4238.   {  savePanel=[SavePanel new];
  4239.   }
  4240.   [savePanel setRequiredFileType:"eve"];
  4241.  
  4242.   if([savePanel runModal])
  4243.   {  // returned w/pathname, open a stream and
  4244.      ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  4245.  
  4246.      NXPrintf(ts, "#\n");
  4247.      NXPrintf(ts, "# This eve 3D text scene file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  4248.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  4249.  
  4250.      [[worldShape tclInterp] writeState:ts];
  4251.  
  4252.      NXPrintf(ts, "set __text__(fontName) %s\n",  [self fontName]);
  4253.      NXPrintf(ts, "set __text__(fontSize) %f\n",  [self fontSize]);
  4254.      NXPrintf(ts, "set __text__(spacing) %f\n",   [self fontSpacing]);
  4255.      NXPrintf(ts, "set __text__(spacingFactor) %f\n",   [self spacingFactor]);
  4256.      NXPrintf(ts, "set __text__(tabLength) %f\n", [self tabLength]);
  4257.      NXPrintf(ts, "set __text__(timeFactor) %f\n", [self timeFactor]);
  4258.      NXPrintf(ts, "set __text__(sampleOffset) %f\n", [self sampleOffset]);
  4259.  
  4260.      // then tell the worldShape to write itself out, which will recurse down...
  4261.  
  4262.      NXPrintf(ts, "startShape TextWorld\n");
  4263.        [worldShape write3DTextScene:ts atTabLevel:1 index:0 time:0 until:((float)-1)];
  4264.      NXPrintf(ts, "endShape\n");
  4265.  
  4266.      // save the stream to the file selected in the savepanel
  4267.      NXSaveToFile(ts, [savePanel filename]);
  4268.  
  4269.      // and close the stream (which also flushes it), also making sure
  4270.      // that the allocated memory is freed.
  4271.     NXCloseMemory(ts,NX_FREEBUFFER);
  4272.   }
  4273.  
  4274.   if (statusText) // potentially record activity
  4275.   {  sprintf(statusBuf, "done!");
  4276.      [statusText setStringValue:statusBuf];
  4277.   }
  4278.   return self;
  4279. }
  4280.  
  4281.  
  4282. - turnOffCropWindow
  4283.    selectionRegion.size.width = 0.0;
  4284.    selectionRegion.size.height = 0.0;
  4285.    return self;
  4286. }
  4287.  
  4288.  
  4289. //RtToken fileContext=NULL, solidContext=NULL;
  4290. //char *archive="archive",*bintype="binaryfile";
  4291.  
  4292. //solidContext=[[N3DContextManager new] mainContext]; // GET THE  
  4293. //CURRENT CONTEXT (USED BY THE 3DKit)
  4294. //fileContext=RiBegin("FileContext","renderer",&archive,"filepath",&ribFile,"format",&asciitype,RI_NULL);
  4295. //// PUT HERE RenderMan code...
  4296. //RiContext(fileContext,RI_NULL); RiEnd();
  4297. //RiContext(solidContext,RI_NULL);
  4298. //[[N3DContextManager new] setCurrentContext:solidContext];
  4299.  
  4300. - dumpBinaryRIBToFile:(char *)filename usingShadingRate:(float)sRate hider:(char *)hiderName pixelSamples:(float)pixelSampleX :(float)pixelSampleY
  4301. {
  4302.   NXRect    myFrame;
  4303.   char      buf[MAXPATHLEN+1];
  4304.   float     cropMinX, cropMinY, cropMaxX, cropMaxY;
  4305.   RtToken  fileContext = NULL, 
  4306.            wwContext = NULL;
  4307.   char     *archive = "archive",
  4308.            *bintype = "binaryfile";
  4309.  
  4310.  
  4311.   wwContext = [[N3DContextManager new] mainContext];
  4312.   fileContext = RiBegin("FileContext", "renderer", &archive, "filepath", &filename, "format", &bintype, RI_NULL);
  4313.  
  4314.   // process the file name for a custom display line such that
  4315.   // "prman <<filename>>.rib" will put the resulting image somewhere
  4316.   // predictably useful.
  4317.   strcpy(buf, filename);
  4318.  
  4319.   // remove the .rib extension from the path returned by the SavePanel
  4320.   strrchr(buf,'.')[0]='\0';
  4321.  
  4322.   // feed to NXPrintf to put in the custom Display command
  4323.   RiArchiveRecord("comment", "This RIB file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.");
  4324.  
  4325.   RiArchiveRecord("comment", "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  4326.   RiArchiveRecord("comment", "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf);
  4327.   RiArchiveRecord("comment", "ShadingRate %f\n", sRate);
  4328.   RiArchiveRecord("comment", "Hider \"%s\"\n", hiderName);
  4329.   RiArchiveRecord("comment", "PixelSamples %f %f\n", pixelSampleX, pixelSampleY);
  4330.  
  4331.   [self getFrame:&myFrame];
  4332.   if ((selectionRegion.size.width > selectionWidthEpsilon)||(selectionRegion.size.height > selectionHeightEpsilon))
  4333.   {  if (selectionRegion.origin.x < 0.0)
  4334.      {  cropMinX = 0.0;
  4335.      }
  4336.      else
  4337.      {  cropMinX = selectionRegion.origin.x/myFrame.size.width;
  4338.      }
  4339.      if ((selectionRegion.size.width + selectionRegion.origin.x) > myFrame.size.width)
  4340.      {  cropMaxX = 1.0;
  4341.      }
  4342.      else
  4343.      {  cropMaxX = (selectionRegion.size.width + selectionRegion.origin.x)/myFrame.size.width;
  4344.      }
  4345.      //////// Y (note Y is flipped) //////////
  4346.      if (selectionRegion.origin.y < 0.0)
  4347.      {  cropMaxY = 1.0;
  4348.      }
  4349.      else
  4350.      {  cropMaxY = 1.0 - (selectionRegion.origin.y/myFrame.size.width);
  4351.      }
  4352.      if ((selectionRegion.size.height + selectionRegion.origin.y) > myFrame.size.height)
  4353.      {  cropMinY = 0.0;
  4354.      }
  4355.      else
  4356.      {  cropMinY = 1.0 - ((selectionRegion.size.height + selectionRegion.origin.y)/myFrame.size.height);
  4357.      }
  4358.      if (cropMinX < 0.0) { cropMinX = 0.0; } 
  4359.      if (cropMinY < 0.0) { cropMinY = 0.0; } 
  4360.      if (cropMaxX > 1.0) { cropMaxX = 1.0; } 
  4361.      if (cropMaxY > 1.0) { cropMaxY = 1.0; } 
  4362.  
  4363.      RiCropWindow(cropMinX, cropMaxX, cropMinY, cropMaxY); 
  4364.   }
  4365.  
  4366.   // need to dump all my camera state here...
  4367.  
  4368.   // now need to tell my worldShape to render itself...
  4369.  
  4370.   return self;
  4371. }
  4372.  
  4373.  
  4374. - dumpRIBToFile:(char *)filename usingShadingRate:(float)sRate hider:(char *)hiderName pixelSamples:(float)pixelSampleX :(float)pixelSampleY
  4375. {
  4376.   NXStream  *ts;
  4377.   NXRect    myFrame;
  4378.   char      buf[MAXPATHLEN+1];
  4379.   float     cropMinX, cropMinY, cropMaxX, cropMaxY;
  4380.  
  4381.   dumpingToRIB = YES;
  4382.  
  4383.   if (statusText) // potentially record activity
  4384.   {  sprintf(statusBuf, "dumping RIB to file %s...", filename);
  4385.      [statusText setStringValue:statusBuf];
  4386.   }
  4387.  
  4388.   // set the output format:
  4389.   if (binaryRIB)
  4390.   {  [self dumpBinaryRIBToFile:filename usingShadingRate:sRate hider:hiderName pixelSamples:pixelSampleX :pixelSampleY];
  4391.   }
  4392.   else
  4393.   {  ts = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  4394.  
  4395.      // process the file name for a custom display line such that
  4396.      // "prman <<filename>>.rib" will put the resulting image somewhere
  4397.      // predictably useful.
  4398.      strcpy(buf, filename);
  4399.  
  4400.      // remove the .rib extension from the path returned by the SavePanel
  4401.      strrchr(buf,'.')[0]='\0';
  4402.  
  4403.      // feed to NXPrintf to put in the custom Display command
  4404.      NXPrintf(ts, "# This RIB file generated by Michael B. Johnson's WW3DKit software running atop NEXTSTEP.\n");
  4405.      NXPrintf(ts, "# Contact him at wave@media.mit.edu or (617) 666-4119 for more information.\n#\n");
  4406.      NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf);
  4407.      NXPrintf(ts, "ShadingRate %f\n", sRate);
  4408.      NXPrintf(ts, "Hider \"%s\"\n", hiderName);
  4409.      NXPrintf(ts, "PixelSamples %f %f\n", pixelSampleX, pixelSampleY);
  4410.      [self getFrame:&myFrame];
  4411.    
  4412.      if ((selectionRegion.size.width > selectionWidthEpsilon)||(selectionRegion.size.height > selectionHeightEpsilon))
  4413.      {  //NXLogError("\n\nselectionRegion.origin == (%f, %f)\t\tselectionRegion.size == (%f, %f)\n", 
  4414.         //        selectionRegion.origin.x, selectionRegion.origin.y, 
  4415.         //        selectionRegion.size.width, selectionRegion.size.height);
  4416.         //NXLogError("myFrame.origin         == (%f, %f)\t\tmyFrame.size         == (%f, %f)\n", 
  4417.         //        myFrame.origin.x, myFrame.origin.y, 
  4418.         //        myFrame.size.width, myFrame.size.height);
  4419.         //////// X //////////
  4420.         if (selectionRegion.origin.x < 0.0)
  4421.         {  cropMinX = 0.0;
  4422.         }
  4423.         else
  4424.         {  cropMinX = selectionRegion.origin.x/myFrame.size.width;
  4425.         }
  4426.    
  4427.         if ((selectionRegion.size.width + selectionRegion.origin.x) > myFrame.size.width)
  4428.         {  cropMaxX = 1.0;
  4429.         }
  4430.         else
  4431.         {  cropMaxX = (selectionRegion.size.width + selectionRegion.origin.x)/myFrame.size.width;
  4432.         }
  4433.    
  4434.         //////// Y (note Y is flipped) //////////
  4435.         if (selectionRegion.origin.y < 0.0)
  4436.         {  cropMaxY = 1.0;
  4437.         }
  4438.         else
  4439.         {  cropMaxY = 1.0 - (selectionRegion.origin.y/myFrame.size.width);
  4440.         }
  4441.    
  4442.         if ((selectionRegion.size.height + selectionRegion.origin.y) > myFrame.size.height)
  4443.         {  cropMinY = 0.0;
  4444.         }
  4445.         else
  4446.         {  cropMinY = 1.0 - ((selectionRegion.size.height + selectionRegion.origin.y)/myFrame.size.height);
  4447.         }
  4448.    
  4449.         //NXLogError("CropWindow %f %f %f %f\n", cropMinX, cropMaxX, cropMinY, cropMaxY); 
  4450.    
  4451.         if (cropMinX < 0.0) { cropMinX = 0.0; } 
  4452.         if (cropMinY < 0.0) { cropMinY = 0.0; } 
  4453.         if (cropMaxX > 1.0) { cropMaxX = 1.0; } 
  4454.         if (cropMaxY > 1.0) { cropMaxY = 1.0; } 
  4455.    
  4456.         NXPrintf(ts, "CropWindow %f %f %f %f\n", cropMinX, cropMaxX, cropMinY, cropMaxY); 
  4457.      }
  4458.      // then feed the rib code to the stream and
  4459.      [self copyRIBCode:ts];
  4460.      // save the stream to the file selected in the savepanel
  4461.      NXSaveToFile(ts, filename);
  4462.    
  4463.      // and close the stream (which also flushes it), also making sure
  4464.      // that the allocated memory is freed.
  4465.      NXCloseMemory(ts,NX_FREEBUFFER);
  4466.    
  4467.      if (statusText) // potentially record activity
  4468.      {  sprintf(statusBuf, "done!");
  4469.         [statusText setStringValue:statusBuf];
  4470.      }
  4471.   }
  4472.  
  4473.   dumpingToRIB = NO;
  4474.   return self;
  4475. }
  4476.  
  4477.  
  4478. - dumpRIBToFile:(char *)filename { return [self dumpRIBToFile:filename usingShadingRate:shadingRate hider:"hidden" pixelSamples:2 :2]; }
  4479.  
  4480.  
  4481. // when the well gets resized, I have to catch this and tell
  4482. // theRotator about it, cause the default doesn't seem to do it (cause it
  4483. // ain't a subview, natch)...
  4484. - sizeTo:(NXCoord)deltaWidth :(NXCoord)deltaHeight
  4485. {
  4486.   NXPoint  aPoint;
  4487.   float    radius;
  4488.  
  4489.  
  4490.   [super sizeTo:deltaWidth :deltaHeight];
  4491.  
  4492.   if (deltaWidth > deltaHeight)
  4493.   {  radius = deltaHeight / 2.0;
  4494.   }
  4495.   else
  4496.   {  radius = deltaWidth / 2.0;
  4497.   }
  4498.   aPoint.x = deltaWidth/2.0;
  4499.   aPoint.y = deltaHeight/2.0;
  4500.  
  4501.   [theRotator setCenter:&aPoint andRadius:radius];
  4502.  
  4503.   return self;
  4504. }
  4505.  
  4506. - setImageFile:(const char *)filename 
  4507. {
  4508.     // It's actually a bad idea to free this image, because it might be shared...
  4509.     // in this case, screw it, cause this has a very specific use...
  4510.    if (filename && *filename)
  4511.    {  image = [NXImage findImageNamed:filename];
  4512.       if (!image) 
  4513.       {  image = [[NXImage alloc] init];
  4514.          [image setDataRetained:YES];
  4515.          if (![image loadFromFile:filename])
  4516.          {  [self setImage:nil];
  4517.             NXLogError("unable to load image from file <%s>\n", filename);
  4518.             return nil; 
  4519.          }
  4520.       }
  4521.    }
  4522.    else
  4523.    {  [self setImage:nil];
  4524.       return nil;
  4525.    }
  4526.  
  4527.    return self;
  4528. }
  4529.  
  4530. - setImage:i  
  4531. {  //if (image) 
  4532.    //{ [image free]; 
  4533.    //} 
  4534.    image = i; 
  4535.    return self; 
  4536. }
  4537.  
  4538. #define SIZE    1
  4539. static float pattern[SIZE] = {2.};
  4540. static float offset = 0;
  4541.  
  4542. - drawPS:(NXRect *)rects :(int)nRects
  4543. {
  4544.   NXPoint p = {0.0, 0.0};
  4545.   NXSize  s;
  4546.  
  4547.    if ((selectionRegion.size.width > selectionWidthEpsilon)||(selectionRegion.size.height > selectionHeightEpsilon))
  4548.    {  PSsetgray(NX_WHITE);
  4549.       PSsetlinewidth(0.0);
  4550.       PSsetdash(pattern,SIZE, offset);
  4551.       PSrectstroke(selectionRegion.origin.x, selectionRegion.origin.y,  
  4552.            selectionRegion.size.width, selectionRegion.size.height);
  4553.  
  4554.       p.x = ((selectionRegion.origin.x) > 0) ? (selectionRegion.origin.x):0;
  4555.       p.y = ((selectionRegion.origin.y) > 0) ? (selectionRegion.origin.y):0;
  4556.   }
  4557.  
  4558.   // there is a bug in 3.2 HP that gets tickled when you have a View
  4559.   // that is 32 bits deep and has qrman drawing into it.  Since I don't
  4560.   // *really* use the fact that there is an alpha component to this image
  4561.   // when I composite it in here, I'm going to punt on doing a "source over"
  4562.   // operation, and just copy it into the View.
  4563.  
  4564.   if (image)
  4565.   {  //NXSetColor(NX_COLORBLACK);
  4566.      //PSsetalpha(1.0);
  4567.      [image getSize:&s];
  4568.      PScompositerect(p.x, p.y, s.width, s.height, NX_COPY); // used to be PScompositerect(p.x, p.y, s.width, s.height, NX_SOVER);
  4569.      [image composite:NX_COPY toPoint:&p]; //used to be [image composite:NX_SOVER toPoint:&p];
  4570.   }
  4571.   return self;
  4572. }
  4573.  
  4574.  
  4575. // need to add timed entries if I'm still holding the modifier down
  4576. // when I exit the inner modal loop.  Use the velocity at exit to set the
  4577. // frequency of the timed entry...
  4578. // When I reenter the mouseDown loop, I should remove any outstanding timed entries.
  4579. // when doing a timed entry, I should record frame rate and display it on the status bar
  4580.  
  4581. - removeAnimateTE
  4582. {
  4583.   if (animateTE)
  4584.   {  DPSRemoveTimedEntry(animateTE);
  4585.      animateTE = 0;
  4586.      animateRotate = NO;
  4587.      // switch back to the N3D_SmoothSolids surface type
  4588.      [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  4589.      RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  4590.   }
  4591.   return self;
  4592. }
  4593.  
  4594.  
  4595. - animateRotate
  4596. {
  4597.   [theRotator trackMouseFrom:&oldMouse to:&newMouse rotationMatrix:rmat andInverse:irmat];
  4598.   [worldShape concatTransformMatrix:rmat premultiply:YES];
  4599.   oldMouse.x =  newMouse.x;
  4600.   oldMouse.y = newMouse.y;
  4601.   newMouse.x += dMouse.x;
  4602.   newMouse.y += dMouse.y;
  4603.   // NXLogError("old == (%f, %f) new == (%f, %f)\n", oldMouse.x, oldMouse.y, newMouse.x, newMouse.y);
  4604.   return self;
  4605. }
  4606.  
  4607.  
  4608. - animateScale
  4609. {
  4610.   return self;
  4611. }
  4612.  
  4613.  
  4614. - animateTranslate
  4615. {
  4616.   return self;
  4617. }
  4618.  
  4619.  
  4620. - animateClick
  4621. {
  4622.   if (animateRotate) { [self animateRotate]; }
  4623.   if (animateScale) { [self animateScale]; }
  4624.   if (animateTranslate) { [self animateTranslate]; }
  4625.   [self display];
  4626.   return self;
  4627. }
  4628.  
  4629.  
  4630. void animateHandler(DPSTimedEntry teNumber, double now, void *userData)
  4631. {
  4632.   id  myObj = (id)userData;
  4633.  
  4634.   [myObj animateClick];
  4635.   return ;
  4636. }
  4637.  
  4638.  
  4639. - removeRenderTE
  4640. {
  4641.   if (renderTE)
  4642.   {  DPSRemoveTimedEntry(renderTE);
  4643.      renderTE = 0;
  4644.      renderCount = 0;
  4645.      backgroundRendering = NO;
  4646.   }
  4647.   return self;
  4648. }
  4649.  
  4650.  
  4651. - setBackgroundRenderingOff  { [self removeRenderTE]; return self; }
  4652.  
  4653. - (BOOL)backgroundRendering { return backgroundRendering; }
  4654.  
  4655. - backgroundRender
  4656. {
  4657.   if (!backgroundRendering)
  4658.   {  renderCount++;
  4659.      if (renderCount == renderAtMediumRate)
  4660.      {  NXLogError("starting medium render...\n");
  4661.         backgroundRendering = YES;
  4662.         [delegate setRenderStartTime];
  4663.         [self renderAsTIFF];
  4664.      }
  4665.      if (renderCount == renderAtHighRate)
  4666.      {  NXLogError("starting high render...\n");
  4667.         backgroundRendering = YES;
  4668.         [delegate setRenderStartTime];
  4669.         [self renderAsTIFF];
  4670.      }
  4671.   }
  4672.   return self;
  4673. }
  4674.  
  4675.  
  4676. void renderHandler(DPSTimedEntry teNumber, double now, void *userData)
  4677. {
  4678.   id  myObj = (id)userData;
  4679.  
  4680.   [myObj backgroundRender];
  4681.   return ;
  4682. }
  4683.  
  4684.  
  4685. ////////////////////////////////////////////////////////////////////
  4686. //            So user can get some feedback
  4687. ///////////////////////////////////////////////////////////////////
  4688.  
  4689. static void getRegion(NXRect *region, const NXPoint *p1, const NXPoint  *p2)
  4690. /*
  4691.  * Returns the rectangle which has p1 and p2 as its corners.
  4692.  */
  4693. {
  4694.     region->size.width = p1->x - p2->x;
  4695.     region->size.height = p1->y - p2->y;
  4696.     if (region->size.width < 0.0) {
  4697.     region->origin.x = p2->x + region->size.width;
  4698.     region->size.width = ABS(region->size.width);
  4699.     } else {
  4700.     region->origin.x = p2->x;
  4701.     }
  4702.     if (region->size.height < 0.0) {
  4703.     region->origin.y = p2->y + region->size.height;
  4704.     region->size.height = ABS(region->size.height);
  4705.     } else {
  4706.     region->origin.y = p2->y;
  4707.     }
  4708. }
  4709.  
  4710. - updateShapeForInteraction:(BOOL)provideUpdates whenTracking:(BOOL)trackShape
  4711. {
  4712.     updateShape = provideUpdates;
  4713.     updateWhenTracking = trackShape;
  4714.     return self;
  4715. }
  4716.  
  4717. - shouldChangeSelected:(BOOL)changeSelected
  4718. {
  4719.     changeSelectedShape = changeSelected;
  4720.     return self;
  4721. }
  4722.  
  4723. // setCurrentShape:theShape
  4724.  
  4725. #define ACTIVEBUTTONMASK (NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK|NX_ALTERNATEMASK|NX_CONTROLMASK|NX_COMMANDMASK)
  4726. - mouseDown:(NXEvent *)theEvent
  4727. {
  4728.   int        oldMask;
  4729.   //NXPoint    p, last, start;
  4730.   //NXRect     visibleRect, oldRegion;
  4731.   NXPoint    start;
  4732.   RtPoint    myEyePoint, 
  4733.              previousEyePoint, previousViewPoint;
  4734.   float      previousRoll;
  4735.   //NXRect selectionRect;
  4736.   long         tmpUsec;
  4737.   struct
  4738.     timeval  renderStartTime, renderFinishTime;
  4739.   char       timeBuf[256];
  4740.   struct
  4741.       timeval  elapsedTime;
  4742.   int          frameCount = 0;
  4743.   float        currentFPS;
  4744.  
  4745.  
  4746.   [self removeAnimateTE];
  4747.   [self removeRenderTE];
  4748.   if (image)
  4749.   {  [image free];
  4750.      image = nil;
  4751.   }
  4752.  
  4753.   dMouse.x = 0.0;
  4754.   dMouse.y = 0.0;
  4755.  
  4756.   // track the mouse until a mouseUp event occurs, updating the display
  4757.   // as tracking happens.
  4758.   [self lockFocus];
  4759.   oldMask = [window addToEventMask:ACTIVEBUTTONMASK];
  4760.   
  4761.   // switch to the N3D_WireFrame surface type
  4762.   [self setSurfaceTypeForAll:movingRenderStyle chooseHider:YES];    
  4763.   RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, lowRezTesselationVector, RI_NULL);
  4764.   
  4765.   oldMouse = theEvent->location;
  4766.   [self convertPoint:&oldMouse fromView:nil];
  4767.   start = oldMouse;
  4768.     
  4769.     /*
  4770.      * Update the current shape should changeSelectedShape be enabled.
  4771.      * setCurrentShape to be complete, or setNoCurrentShape should
  4772.      * the mouseDown occur outside of any bounding box (for those
  4773.      * shapes that are selectable).
  4774.      */
  4775.     if (changeSelectedShape) {
  4776.     id theShape = worldShape;
  4777.     NXRect boundingRect;
  4778.     
  4779.     while (theShape) {
  4780.         if ([theShape conformsTo:@protocol(WWRenderable)]) {
  4781.         (void)[theShape boundingBox];
  4782.         }
  4783.         [theShape getBounds:&boundingRect inCamera:self];
  4784.         if (NXPointInRect(&start, &boundingRect)) {
  4785.         [self setCurrentShape:theShape];
  4786.         break;
  4787.         }
  4788.         theShape = [theShape nextPeer];
  4789.     }
  4790.     if (!theShape) {
  4791.         [self setNoCurrentShape:self];
  4792.     }
  4793. #if 0
  4794.     List *selected;
  4795.     
  4796.     NXSetRect(&selectionRect, start.x, start.y, 10.0, 10.0);
  4797.     selected = [self selectShapesIn:&selectionRect];
  4798.     if ([selected count] == 0) {
  4799.         [self setNoCurrentShape:self];
  4800.     } else {
  4801.         [self setCurrentShape:[selected objectAt:0]];
  4802.     }
  4803. #endif
  4804.     }
  4805.     
  4806.   // when the alt key is depressed, we scale the worldShape up or down, depending on mouse movement.
  4807.   // otherwise, we rotate the worldShape using the virtual trackball
  4808.  
  4809.   gettimeofday(&renderStartTime, 0);
  4810.   while (1)
  4811.   { newMouse = theEvent->location;
  4812.     [self convertPoint:&newMouse fromView:nil];
  4813.     dMouse.x = newMouse.x - oldMouse.x;
  4814.     dMouse.y = newMouse.y - oldMouse.y;
  4815.     if (dMouse.x != 0.0 || dMouse.y != 0.0) 
  4816.     {  if (theEvent->flags & NX_ALTERNATEMASK)
  4817.        {  switch (trackballAffects)
  4818.       {  case WW_TRACKBALL_WORLD_SHAPE:
  4819.                  sprintf(statusBuf, "translating world in Z by %f", (translateZFactor * dMouse.y));
  4820.                  [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4821.          [worldShape translate:0.0 :0.0 :(translateZFactor * dMouse.y)];
  4822.          break;
  4823.          case WW_TRACKBALL_CURRENT_SHAPE:
  4824.                  sprintf(statusBuf, "translating %s in Z by %f", [currentShape shapeName], (translateZFactor * dMouse.y));
  4825.                  [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4826.          [currentShape translate:0.0 :0.0 :(translateZFactor * dMouse.y)];
  4827.          break;
  4828.          case WW_TRACKBALL_CAMERA:
  4829.          // need to change Eye point
  4830.                  sprintf(statusBuf, "moving eye point in Z by %f", (translateZFactor * dMouse.y));
  4831.                  [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4832.          [self moveEyeBy:0.0 :0.0 :(-1. * (translateZFactor * dMouse.y))];
  4833.          break;
  4834.       }
  4835.        }
  4836.        else
  4837.        {  if (theEvent->flags & NX_CONTROLMASK)
  4838.       {  // NOTE draw rubber band selection here
  4839.          getRegion(&selectionRegion, &newMouse, &start);
  4840.              [statusText setStringValue:"selecting crop region for rendering..."]; [statusText display]; NXPing();
  4841.          //NXInsetRect(&oldRegion, -1.0, -1.0);
  4842.          //oldRegion = selectionRegion;
  4843.          // last = p;
  4844.           }
  4845.           else
  4846.       {  if (theEvent->flags & NX_COMMANDMASK)
  4847.              {  switch (trackballAffects)
  4848.           {  case WW_TRACKBALL_WORLD_SHAPE:
  4849.                     sprintf(statusBuf, "translating world in X & Y by (%f, %f)", (translateXFactor * dMouse.x), (translateYFactor * dMouse.y));
  4850.                     [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4851.             [worldShape translate:(translateXFactor * dMouse.x) 
  4852.                                          :(translateYFactor * dMouse.y) :0.0];
  4853.             break;
  4854.            case WW_TRACKBALL_CURRENT_SHAPE:
  4855.                     sprintf(statusBuf, "translating %s in X & Y by (%f, %f)", 
  4856.                             [currentShape shapeName], (translateXFactor * dMouse.x), (translateYFactor * dMouse.y));
  4857.                     [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4858.             [currentShape translate:(translateXFactor * dMouse.x) 
  4859.                                            :(translateYFactor * dMouse.y) :0.0];
  4860.                     break;
  4861.               case WW_TRACKBALL_CAMERA:
  4862.                     sprintf(statusBuf, "moving eye in X & Y by (%f, %f)", (translateXFactor * dMouse.x), (translateYFactor * dMouse.y));
  4863.                     [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4864.                     [self moveEyeBy:(-1. * (translateXFactor * dMouse.x)) 
  4865.                              :(-1. * (translateYFactor * dMouse.y)) :0.0];
  4866.             break;
  4867.             }
  4868.          }
  4869.              else
  4870.              {  [theRotator trackMouseFrom:&oldMouse to:&newMouse rotationMatrix:rmat andInverse:irmat];
  4871.                 switch (trackballAffects)
  4872.         {  case WW_TRACKBALL_WORLD_SHAPE:
  4873.                        sprintf(statusBuf, "rotating world...");
  4874.                        [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4875.                [worldShape concatTransformMatrix:rmat premultiply:YES];
  4876.                        break;
  4877.            case WW_TRACKBALL_CAMERA:
  4878.                        sprintf(statusBuf, "rotating camera...");
  4879.                        [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4880.                [self getEyeAt:&previousEyePoint toward:&previousViewPoint roll:&previousRoll];   
  4881.                        myEyePoint[0] = previousEyePoint[0] + (-1. * (translateXFactor * dMouse.x)); 
  4882.                        myEyePoint[1] = previousEyePoint[1] + (-1. * (translateYFactor * dMouse.y)); 
  4883.                        myEyePoint[2] = previousEyePoint[2];
  4884.                [self setEyeAt:myEyePoint toward:previousViewPoint roll:previousRoll];   
  4885.                        break;
  4886.            case WW_TRACKBALL_CURRENT_SHAPE:
  4887.                        sprintf(statusBuf, "rotating %s...", [currentShape shapeName]);
  4888.                        [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  4889.                [currentShape concatTransformMatrix:rmat premultiply:YES];
  4890.                        break;
  4891.         }
  4892.          } 
  4893.       }
  4894.        }
  4895.     if (updateShape && updateWhenTracking) {
  4896.         if (trackballAffects == WW_TRACKBALL_WORLD_SHAPE) {
  4897.         [worldShape performUpdateForInteraction:self];
  4898.         } else if (trackballAffects == WW_TRACKBALL_CURRENT_SHAPE) {
  4899.         [currentShape performUpdateForInteraction:self];
  4900.         }
  4901.     }
  4902.        [self display];
  4903.        NXPing();
  4904.     }
  4905.     theEvent = [NXApp getNextEvent:ACTIVEBUTTONMASK];
  4906.     if (theEvent->type == NX_MOUSEUP)
  4907.     {  break;
  4908.     }
  4909.     else
  4910.     {  oldMouse = newMouse;
  4911.     }
  4912.     frameCount++;
  4913.   }
  4914.   gettimeofday(&renderFinishTime, 0);
  4915.   [statusText setStringValue:"done"]; [statusText display]; NXPing();
  4916.  
  4917.   elapsedTime.tv_sec = renderFinishTime.tv_sec  - renderStartTime.tv_sec;
  4918.   tmpUsec = renderFinishTime.tv_usec - renderStartTime.tv_usec;
  4919.   if (tmpUsec < 0)
  4920.   {  elapsedTime.tv_sec--;
  4921.      elapsedTime.tv_usec = (long)1000000 + tmpUsec;
  4922.   }
  4923.   else
  4924.   {  elapsedTime.tv_usec = tmpUsec;
  4925.   }
  4926.   if (elapsedTime.tv_usec > (long)1000000)
  4927.   {  elapsedTime.tv_sec++;
  4928.      elapsedTime.tv_usec -= (long)1000000;
  4929.   }
  4930.  
  4931.   if (frameCount)
  4932.   {  currentFPS = (float)frameCount/((float)elapsedTime.tv_sec + ((float)(elapsedTime.tv_usec)/1000000.));
  4933.      sprintf(timeBuf, 
  4934.          "%f fps: %d frames in %d.%d seconds", 
  4935.          currentFPS, frameCount, (int)(elapsedTime.tv_sec), (int)((1000000 - elapsedTime.tv_usec)/100000));
  4936.      [statusText setStringValue:timeBuf]; [statusText display]; NXPing();
  4937.   }
  4938.  
  4939.   // check to see if we should go off and render (need a minimum image size, like 16x16)...
  4940.  
  4941.   // check to see if we should keep rotating or scaling...
  4942.   // if mouse was moving significantly, keep going...
  4943.   if (((float)fabs((double)(dMouse.x)) > epsilon) || ((float)fabs((double)dMouse.y) > epsilon))
  4944.   {  // comment out for now...
  4945.      //animateTE = DPSAddTimedEntry(.002, (DPSTimedEntryProc)animateHandler, self, NX_BASETHRESHOLD);
  4946.      //animateRotate = YES;
  4947.      [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  4948.      RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  4949.   }
  4950.   else
  4951.   {  animateTE = 0;
  4952.      animateRotate = NO;
  4953.      // switch back to the N3D_SmoothSolids surface type
  4954.      [self setSurfaceTypeForAll:renderStyle chooseHider:YES];    
  4955.      RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, tesselationVector, RI_NULL);
  4956.  
  4957.      //renderTE = DPSAddTimedEntry(renderCheckTimeSlice, (DPSTimedEntryProc)renderHandler, self, NX_BASETHRESHOLD);
  4958.   }
  4959.     if (updateShape) {
  4960.     if (trackballAffects == WW_TRACKBALL_WORLD_SHAPE) {
  4961.         [worldShape performUpdateForInteraction:self];
  4962.     } else if (trackballAffects == WW_TRACKBALL_CURRENT_SHAPE) {
  4963.         [currentShape performUpdateForInteraction:self];
  4964.     }
  4965.     }
  4966.   [self display];
  4967.   [self unlockFocus];
  4968.   [window setEventMask:oldMask];
  4969.   [window flushWindow];
  4970.  
  4971.   return self;
  4972. }
  4973.  
  4974. - (BOOL)acceptsFirstResponder { return YES; }
  4975.  
  4976. - (BOOL)acceptsFirstMouse { return YES; }
  4977.  
  4978. - keyDown:(NXEvent *)theEvent
  4979. {
  4980. //  id  theCmd = nil;
  4981.  
  4982.  
  4983.   // what we want to be able to do is have a set of mappings from the
  4984.   // charCode to some piece of tcl code.
  4985.   // We also want to be able to have the tcl code be executed in either
  4986.   // the camera's interp or the shape interp...
  4987.   // we'll say that if the cmd key is held down, it goes to the camera,
  4988.   // otherwise we send it to the root shape's interp.
  4989.  
  4990.   // we should probably have a hash table which has two things:
  4991.   // the charCode and the tcl code that corresponds to it
  4992.   // if there isn't an entry, drop through...
  4993.  
  4994. //  if (theEvent->flags & NX_COMMANDMASK)  // the command key is being held down : camera!
  4995. //  {  theCmd = [self cameraCmdFromCharCode:theEvent->data.key.charCode];
  4996. //     if (theCmd)
  4997. //     {  [tclInterp globalEval:[theCmd str]];
  4998. //     }
  4999. //     [delegate controlsWereUpdated:self];
  5000. //     return self;
  5001. //  }
  5002. //  else // must want to talk to the model, I guess...
  5003. //  {  theCmd = [self modelCmdFromCharCode:theEvent->data.key.charCode];
  5004. //     if (theCmd)
  5005. //     {  [[rootShape tclInterp] globalEval:[theCmd str]];
  5006. //     }
  5007. //     [delegate controlsWereUpdated:self];
  5008. //     return self;
  5009. //  }
  5010.  
  5011.   return [super keyDown:theEvent];
  5012. }
  5013.  
  5014. - takeRenderWorldAsBox:sender 
  5015.    drawWorldAsBox = [sender intValue]; 
  5016.    [worldShape setDrawAsBox:drawWorldAsBox];
  5017.    return [self display]; 
  5018. }
  5019. - takeRenderCurrentAsBox:sender 
  5020. {
  5021.    drawCurrentAsBox = [sender intValue]; 
  5022.    [currentShape setDrawAsBox:drawCurrentAsBox];
  5023.    return [self display]; 
  5024. }
  5025.  
  5026. - takeWorldIsVisible:sender { [worldShape setVisible:[sender intValue]]; return [self display]; }
  5027. - takeCurrentIsVisible:sender { [currentShape setVisible:[sender intValue]]; return [self display]; }
  5028.  
  5029. - (BOOL)renderWorldAsBox { return [worldShape doesDrawAsBox]; }
  5030. - (BOOL)renderCurrentAsBox { return [currentShape doesDrawAsBox]; }
  5031. - (BOOL)worldIsVisible { return [worldShape isVisible]; }
  5032. - (BOOL)currentIsVisible { return [currentShape isVisible]; }
  5033.  
  5034. - (int)trackballAffects { return trackballAffects; }
  5035. - takeTrackballAffectsFromMatrix:sender
  5036. {
  5037.   int  newVal = [[sender selectedCell] tag];
  5038.  
  5039.  
  5040.   switch (newVal)
  5041.   {  case WW_TRACKBALL_WORLD_SHAPE:
  5042.      trackballAffects = newVal;
  5043.          [self setUsePreTransformMatrix:NO];
  5044.      break;
  5045.      case WW_TRACKBALL_CAMERA:
  5046.      // we assume that [self usesPreTransformMatrix] returns YES...
  5047.      trackballAffects = newVal;
  5048.          [self setUsePreTransformMatrix:YES];
  5049.       break;
  5050.      case WW_TRACKBALL_CURRENT_SHAPE:
  5051.      trackballAffects = newVal;
  5052.          [self setUsePreTransformMatrix:NO];
  5053.      break;
  5054.      default:
  5055.      NXLogError("%d is an invalid value for trackballAffects.\n", newVal);
  5056.      } 
  5057.  
  5058.  
  5059.   return self;
  5060. }
  5061.  
  5062. - (int)trackballXYZ 
  5063.   N3DAxis  theAxis  = [theRotator rotationAxis];
  5064.   int      theAxisInt = -1;
  5065.  
  5066.  
  5067.   if (theAxis == N3D_AllAxes) { theAxisInt = 0; }
  5068.  
  5069.   if (theAxis == N3D_XAxis) { theAxisInt = 1; }
  5070.   if (theAxis == N3D_YAxis) { theAxisInt = 2; }
  5071.   if (theAxis == N3D_ZAxis) { theAxisInt = 3; }
  5072.  
  5073.   if (theAxis == N3D_XYAxes) { theAxisInt = 4; }
  5074.   if (theAxis == N3D_XZAxes) { theAxisInt = 5; }
  5075.   if (theAxis == N3D_YZAxes) { theAxisInt = 6; }
  5076.  
  5077.   return theAxisInt;
  5078. }
  5079.  
  5080. - takeTrackballXYZFromMatrix:sender
  5081. {
  5082.   int  newVal = [[sender selectedCell] tag];
  5083.  
  5084.   switch (newVal)
  5085.   {  case 0:
  5086.      [theRotator setRotationAxis:N3D_AllAxes];
  5087.      break;
  5088.      case 1:
  5089.      [theRotator setRotationAxis:N3D_XAxis];
  5090.      break;
  5091.      case 2:
  5092.      [theRotator setRotationAxis:N3D_YAxis];
  5093.      break;
  5094.      case 3:
  5095.      [theRotator setRotationAxis:N3D_ZAxis];
  5096.      break;
  5097.      case 4:
  5098.      [theRotator setRotationAxis:N3D_XYAxes];
  5099.      break;
  5100.      case 5:
  5101.      [theRotator setRotationAxis:N3D_XZAxes];
  5102.      break;
  5103.      case 6:
  5104.      [theRotator setRotationAxis:N3D_YZAxes];
  5105.      break;
  5106.      default:
  5107.      NXLogError("%d is an invalid value for trackballXYZ.\n", newVal);
  5108.      } 
  5109.   return self;
  5110. }
  5111.  
  5112.  
  5113. - tclInterp { return tclInterp; }
  5114.  
  5115.  
  5116. /// new camera stuff
  5117. - takeFocalLength:sender  {  return [self setFocalLength:[sender floatValue]];  }
  5118. - takeFocalDistance:sender {  return [self setFocalDistance:[sender floatValue]]; }
  5119. - takeFStop:sender {  return [self setFStop:[sender floatValue]]; }
  5120. - takeExposureLength:sender {  return [self setExposureLength:[sender floatValue]]; }
  5121.  
  5122. - takeShotOutputTypeFromMatrix:sender 
  5123. {  NXLogError("[WW3DCamera takeShotOutputTypeFromMatrix:sender] is not really implemented yet.\n");
  5124.    shotOutputType = [[sender selectedCell] tag]; 
  5125.    return self;
  5126. }
  5127.  
  5128. - takeShotLength:sender  {  return [self setShotLength:[sender floatValue]];  }
  5129. - takeFramesPerSecond:sender {  return [self setFramesPerSecond:[sender floatValue]]; }
  5130. - takeFrameNumber:sender {  return [self setFrameNumber:[sender intValue]]; }
  5131.  
  5132. - takeExposureLengthFactor:sender { return [self setExposureLengthFactor:[sender floatValue]]; }
  5133. - takeShotStartTime:sender  {  return [self setShotStartTime:[sender floatValue]];  }
  5134.  
  5135.  
  5136. - setRenderStyle:(int)s { renderStyle = s; [self setSurfaceTypeForAll:renderStyle chooseHider:YES]; [self display]; return self; }
  5137. - (int)renderStyle { return renderStyle; }
  5138.  
  5139. - setMovingRenderStyle:(int)s { movingRenderStyle = s; return self; }
  5140. - (int)movingRenderStyle { return movingRenderStyle; }
  5141.  
  5142. - (NXColor) backgroundColor     { return backgroundColor; }
  5143. - setBackgroundColor:(NXColor)c { backgroundColor = c; [self display]; return self; }
  5144.  
  5145. - (BOOL)showSelectedShape { return showSelectedShape; }
  5146. - setShowSelectedShape:(BOOL)flag 
  5147.    showSelectedShape = flag; 
  5148.    [currentShape setSelected:flag andDrawOrigin:drawOriginForSelectedShape];
  5149.    [self display];
  5150.    return self; 
  5151. }
  5152.  
  5153. - setSceneClock:newSceneClock { sceneClock = newSceneClock; return self; }
  5154. - sceneClock { return sceneClock; }
  5155.  
  5156. - (BOOL)drawOriginForSelectedShape { return drawOriginForSelectedShape; }
  5157. - setDrawOriginForSelectedShape:(BOOL)flag 
  5158.    drawOriginForSelectedShape = flag; 
  5159.    [currentShape setDrawOrigin:flag];
  5160.    [self display];
  5161.    return self; 
  5162. }
  5163.  
  5164. - otherLightList { return otherLightList; }
  5165.  
  5166. - addLocalLight:light usingPath:(const char *)aParentPath 
  5167.   id theLightParent = [[self worldShape] getChildGivenPath:aParentPath];
  5168.  
  5169.  
  5170.   if (theLightParent)
  5171.   {  [theLightParent addChild:light];
  5172.      [otherLightList addObject:light];
  5173.      return self;
  5174.   }
  5175.   return nil;
  5176. }
  5177.  
  5178. - setStatusText:newStatusText { statusText = newStatusText; return self; }
  5179. - statusText { return statusText; }
  5180.  
  5181. - (BOOL)useRendribInstead { return useRendribInstead; }
  5182. - setUseRendribInstead:(BOOL)n { useRendribInstead = n; return self; }
  5183. - takeUseRendribInstead:sender { useRendribInstead = [sender intValue]; return self; }
  5184.  
  5185. - (BOOL)binaryRIB { return binaryRIB; }
  5186. - setBinaryRIB:(BOOL)n { binaryRIB = n; return self; }
  5187. - takeBinaryRIB:sender { binaryRIB = [sender intValue]; return self; }
  5188.  
  5189.  
  5190. #define typeVectorVersion1 "i*ffffffff@[2f][2f]fiifcci@cffffffff@@@"
  5191. #define typeValuesVersion1 &renderStyle, &ribName, \
  5192.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  5193.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  5194.         &image, &lowRezTesselationVector, &tesselationVector, &shadingRate, \
  5195.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  5196.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  5197.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  5198.         &ambientLight, &leftLight, &rightLight
  5199.  
  5200.  
  5201. #define typeVectorVersion2 "i*ffffffff@[2f][2f]fiifcci@cffffffff@@@"
  5202. #define typeValuesVersion2 &renderStyle, &ribName, \
  5203.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  5204.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  5205.         &image, &lowRezTesselationVector, &tesselationVector, &shadingRate, \
  5206.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  5207.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  5208.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  5209.         &ambientLight, &leftLight, &rightLight
  5210.  
  5211.  
  5212. #define typeVectorVersion3 "i*ffffffff@fiifcci@cffffffff@@@"
  5213. #define typeValuesVersion3 &renderStyle, &ribName, \
  5214.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  5215.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  5216.         &image, &shadingRate, \
  5217.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  5218.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  5219.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  5220.         &ambientLight, &leftLight, &rightLight
  5221.  
  5222. #define typeVector "i*ffffffff@fiifcci@cffffffff@@@ff"
  5223. #define typeValues &renderStyle, &ribName, \
  5224.         &scaleUpFactor, &scaleDownFactor, &translateXFactor, &translateYFactor, &translateZFactor, \
  5225.         &epsilon, &selectionWidthEpsilon, &selectionHeightEpsilon, \
  5226.         &image, &shadingRate, \
  5227.         &renderAtMediumRate, &renderAtHighRate, &renderCheckTimeSlice, &showSelectedShape, &drawOriginForSelectedShape, \
  5228.         &movingRenderStyle, &tclInterp, &defaultLightsInUse, \
  5229.         &fStop, &focalLength, &focalDistance, &shutterOpenTime, &exposureLength, &frameTimeIncrement, &shotLength, &framesPerSecond, \
  5230.         &ambientLight, &leftLight, &rightLight, &shotStartTime, &exposureLengthFactor
  5231.  
  5232.  
  5233. - read:(NXTypedStream *)stream
  5234. {
  5235.     int version;
  5236.     
  5237.     [super read:stream];
  5238.     
  5239.     NX_DURING
  5240.     version = NXTypedStreamClassVersion(stream, "WW3DCamera");
  5241.     if (version == 0) NXReadTypes(stream,"i",&version), version=1;
  5242.     if (version == 1) {
  5243.         NXReadTypes(stream, typeVectorVersion1, typeValuesVersion1);
  5244.         backgroundColor = NXReadColor(stream);
  5245.         ribColor = NXReadColor(stream);
  5246.         shotStartTime = 0.0;
  5247.         exposureLengthFactor = 1.0;
  5248.             binaryRIB = NO;
  5249.     }
  5250.     if (version == 2) {
  5251.         NXReadTypes(stream, typeVectorVersion2, typeValuesVersion2);
  5252.         backgroundColor = NXReadColor(stream);
  5253.         ribColor = NXReadColor(stream);
  5254.         shotStartTime = 0.0;
  5255.         exposureLengthFactor = 1.0;
  5256.             binaryRIB = YES;
  5257.     }
  5258.     if (version == 3) {
  5259.         NXReadTypes(stream, typeVectorVersion3, typeValuesVersion3);
  5260.         NXReadArray(stream, "f", 2, lowRezTesselationVector);
  5261.         NXReadArray(stream, "f", 2, tesselationVector);
  5262.         backgroundColor = NXReadColor(stream);
  5263.         ribColor = NXReadColor(stream);
  5264.         sceneClock = NXReadObject(stream);
  5265.         shotStartTime = 0.0;
  5266.         exposureLengthFactor = 1.0;
  5267.             binaryRIB = NO;
  5268.     }
  5269.     if (version == 4) {
  5270.         NXReadTypes(stream, typeVector, typeValues);
  5271.         NXReadArray(stream, "f", 2, lowRezTesselationVector);
  5272.         NXReadArray(stream, "f", 2, tesselationVector);
  5273.         backgroundColor = NXReadColor(stream);
  5274.         ribColor = NXReadColor(stream);
  5275.         sceneClock = NXReadObject(stream);
  5276.             binaryRIB = NO;
  5277.     }
  5278.     if (version == 5) {
  5279.         NXReadTypes(stream, typeVector, typeValues);
  5280.         NXReadArray(stream, "f", 2, lowRezTesselationVector);
  5281.         NXReadArray(stream, "f", 2, tesselationVector);
  5282.         backgroundColor = NXReadColor(stream);
  5283.         ribColor = NXReadColor(stream);
  5284.         sceneClock = NXReadObject(stream);
  5285.         NXReadType(stream, "c", &binaryRIB);
  5286.     }
  5287.     NX_HANDLER
  5288.     NXLogError("in read: %s, exception [%d] raised.\n", [[self class] name], NXLocalHandler.code);
  5289.     return nil;
  5290.     NX_ENDHANDLER
  5291.     return self;
  5292. }
  5293.  
  5294. - write:(NXTypedStream *)stream 
  5295. {
  5296.     [super write:stream];
  5297.     exposureLength = savedExposureLength;  // just to make sure we archive it...
  5298.     NXWriteTypes(stream, typeVector, typeValues);
  5299.     NXWriteArray(stream, "f", 2, lowRezTesselationVector);
  5300.     NXWriteArray(stream, "f", 2, tesselationVector);
  5301.     NXWriteColor(stream, backgroundColor);
  5302.     NXWriteColor(stream, ribColor);
  5303.     NXWriteObjectReference(stream, sceneClock);
  5304.     NXWriteType(stream, "c", &binaryRIB);
  5305.     return self;
  5306. }
  5307.  
  5308. @end
  5309.