home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / Wave / WavesWorld / Source / IBPalettes / WW3DKit / WW3DShader.m < prev    next >
Encoding:
Text File  |  1995-04-03  |  30.0 KB  |  1,046 lines

  1. // copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
  2. // see COPYRIGHT for reuse legalities
  3. //
  4.  
  5. #import "WW3DShader.h"
  6. #import <3Dkit/3Dkit.h>
  7.  
  8. #import "WWShaderArgPointMatrix.h"
  9. #import "WWEveParser.h"
  10.  
  11. @implementation WW3DShader
  12.  
  13. + initialize { return [WW3DShader setVersion:4], self; }
  14.  
  15. static lightHandleSeed = 0;
  16.  
  17. static BOOL
  18. validQuickShader(const char *name)
  19. {
  20.   if (!name)
  21.   {  return NO;
  22.   }
  23.   if (!strcmp("plastic", name))
  24.   {  return YES;
  25.   }
  26.   if (!strcmp("paintedplastic", name))
  27.   {  return YES;
  28.   }
  29.   if (!strcmp("constant", name))
  30.   {  return YES;
  31.   }
  32.   if (!strcmp("matte", name))
  33.   {  return YES;
  34.   }
  35.   if (!strcmp("metal", name))
  36.   {  return YES;
  37.   }
  38.   if (!strcmp("shinymetal", name))
  39.   {  return YES;
  40.   }
  41.   if (!strcmp("ambientlight", name))
  42.   {  return YES;
  43.   }
  44.   if (!strcmp("distantlight", name))
  45.   {  return YES;
  46.   }
  47.   if (!strcmp("pointlight", name))
  48.   {  return YES;
  49.   }
  50.   if (!strcmp("spotlight", name))
  51.   {  return YES;
  52.   }
  53.   if (!strcmp("depthcue", name))
  54.   {  return YES;
  55.   }
  56.   if (!strcmp("fog", name))
  57.   {  return YES;
  58.   }
  59.   if (!strcmp("bumpy", name))
  60.   {  return YES;
  61.   }
  62.   return NO;
  63. }
  64.  
  65. - init
  66. {
  67.   if (![super init])
  68.   {  return nil;
  69.   }
  70.  
  71.   // for each of the tokens, we need to see if it corresponds to a
  72.   //  valid argument of this shader.  If it does, we set the value 
  73.   // using the corresponding parm.
  74.   n = 0;
  75.   tokens = NULL;
  76.   parms = NULL;
  77.   archiveVector = NULL;
  78.   printfNVector = NULL;
  79.   printfTypeVector = NULL;
  80.   iconImage = [NXImage findImageNamed:"shader"];
  81.   [self assignQuickShader];
  82.   usingSupportedQRManShader = NO;
  83.  
  84.   lightHandle = 0;
  85.  
  86.   // dis ain't dat portable, ya know...
  87.   ribColor[0] = 1.0;
  88.   ribColor[1] = 1.0;
  89.   ribColor[2] = 1.0;
  90.  
  91.   return self;
  92. }
  93.  
  94.  
  95. - (BOOL)pushesOrPopsCTM { return NO; }
  96. - (BOOL)pushesCTM { return NO; }
  97. - (BOOL)popsCTM { return NO; }
  98.  
  99. - initWithShader:(const char *)shaderName n:(int)newN tokens:(RtToken *)newTokens parms:(RtPointer *)newParms archiveVector:(char **)newArchiveVector printfTypeVector:(int *)newPrintfTypeVector printfNVector:(int *)newPrintfNVector
  100. {
  101.   int  i;
  102.  
  103.  
  104.   if (![super initWithShader:shaderName])
  105.   {  return nil;
  106.   }
  107.  
  108.   [self setShader:shaderName];
  109.   [self setUseColor:NO];
  110.  
  111.   // for each of the tokens, we need to see if it corresponds to a
  112.   //  valid argument of this shader.  If it does, we set the value 
  113.   // using the corresponding parm.
  114.   n = newN;
  115.   tokens = newTokens;
  116.   parms = newParms;
  117.   archiveVector = newArchiveVector;
  118.   printfNVector = (int *)malloc(n * sizeof(int));
  119.   printfTypeVector = (int *)malloc(n * sizeof(int));
  120.  
  121.   for (i = 0; i < n; i++)
  122.   {  if (![self setShaderArgNamed:tokens[i] withValue:parms[i]])
  123.      {  NXLogError("in shader %s, <%s> is not a valid arg.\n", 
  124.            shaderName, tokens[i]);
  125.      }
  126.      printfNVector[i] = newPrintfNVector[i];
  127.      printfTypeVector[i] = newPrintfTypeVector[i];
  128.   }
  129.  
  130.   lightHandle = 0;
  131.  
  132.   // dis ain't dat portable, ya know...
  133.   ribColor[0] = 1.0;
  134.   ribColor[1] = 1.0;
  135.   ribColor[2] = 1.0;
  136.  
  137.   return self;
  138. }
  139.  
  140. - setShader:(const char *)name
  141. {
  142.   if (![super setShader:name])
  143.   {  return nil;
  144.   }
  145.   if (name)
  146.   {  iconImage = [NXImage findImageNamed:(char *)name];
  147.   }
  148.   else
  149.   {  iconImage = nil;
  150.   }
  151.   if (!iconImage)
  152.   {  iconImage = [NXImage findImageNamed:"shader"];
  153.   }
  154.   if (validQuickShader(name))
  155.   {  quickShader = NXCopyStringBuffer(name);
  156.      usingSupportedQRManShader = YES;
  157.   }
  158.   else
  159.   {  [self assignQuickShader];
  160.      usingSupportedQRManShader = NO;
  161.   }
  162.  
  163.   return self;
  164. }
  165.  
  166. - assignQuickShader
  167. {
  168.   if (quickShader) {  free(quickShader); }
  169.   switch ([self shaderType])
  170.   {  
  171.      case SLO_TYPE_SURFACE:
  172.        // really should be arbitrarily smart here
  173.        // you can look at the parameters of the shaders, etc. to try and figure out which it use
  174.        // for now, just just use plastic.
  175.        quickShader = NXCopyStringBuffer("plastic");
  176.        break;
  177.  
  178.      case SLO_TYPE_LIGHT:
  179.        quickShader = NXCopyStringBuffer("pointlight");
  180.        break;
  181.  
  182.      case SLO_TYPE_DISPLACEMENT:
  183.        quickShader = NXCopyStringBuffer("bumpy");
  184.        break;
  185.  
  186.      case SLO_TYPE_VOLUME:
  187.        // need to figure out what kind...
  188.        quickShader = NXCopyStringBuffer("depthcue");
  189.        break;
  190.  
  191.      case SLO_TYPE_TRANSFORMATION:
  192.        quickShader = NULL;
  193.        break;
  194.  
  195.      case SLO_TYPE_IMAGER:
  196.        quickShader = NULL;
  197.        break;
  198.  
  199.      default:
  200.        quickShader = NULL;
  201.        return nil;
  202.   }
  203.  
  204.   return self;
  205. }
  206.  
  207. - setShaderArgNamed:(const char *)argName withValue:(RtPointer)value
  208. {
  209.   SLO_TYPE   argType;
  210.  
  211.  
  212.   argType = [self shaderArgType:argName];
  213.   if (argType == SLO_TYPE_POINT)
  214.   {  return [self setShaderArg:argName pointValue:*((RtPoint *)value)];
  215.   }
  216.   if (argType == SLO_TYPE_COLOR)
  217.   {  // note that it wants an NXColor, not an RtColor...
  218.      RtFloat r = *((RtFloat *)value); 
  219.      RtFloat g = *((RtFloat *)(value+sizeof(RtFloat))); 
  220.      RtFloat b = *((RtFloat *)(value+(2*sizeof(RtFloat))));
  221.      NXColor  anNXColor = NXConvertRGBToColor((float)r, (float)g, (float)b);
  222.      
  223.      return [self setShaderArg:argName colorValue:anNXColor];
  224.   }
  225.   if (argType == SLO_TYPE_SCALAR)
  226.   {  return [self setShaderArg:argName floatValue:(*((RtFloat *)value))];
  227.   }
  228.   if (argType == SLO_TYPE_STRING)
  229.   {  return [self setShaderArg:argName stringValue:(*(char **)value)];
  230.   }
  231.  
  232.   return nil;
  233. }
  234.  
  235.  
  236. - (const char *)quickShader {  return quickShader; }
  237. - setQuickShader:(const char *)newQuickShader 
  238. {  
  239.    if (!validQuickShader(newQuickShader))
  240.    {  NXLogError("%s is not a shader supported by qrman, yabba-head!\n");
  241.       return nil;
  242.    }
  243.    if (quickShader)
  244.    {  free(quickShader);
  245.    }
  246.    quickShader = NXCopyStringBuffer(newQuickShader);
  247.    return self;
  248. }
  249.  
  250. - setColor:(NXColor)aColor
  251. {
  252.   ribColor[0] = NXRedComponent(aColor);
  253.   ribColor[1] = NXGreenComponent(aColor);
  254.   ribColor[2] = NXBlueComponent(aColor);
  255.   return [super setColor:aColor];
  256. }
  257.  
  258. - (RtToken)token { return token; }
  259.  
  260. - setToken:(RtToken)newToken
  261. {
  262.   token = newToken;
  263.   return self;
  264. }
  265.  
  266. - set
  267. {
  268.   if (NXDrawingStatus == NX_DRAWING)
  269.   {  
  270.      if ([self doesUseColor])
  271.      {  RiColor(ribColor);
  272.      }
  273.      if (quickShader)
  274.      {  switch ([self shaderType])
  275.         {  
  276.            case SLO_TYPE_SURFACE:
  277.              RiSurfaceV(quickShader, n, tokens, parms);
  278.              break;
  279.  
  280.           case SLO_TYPE_LIGHT:
  281.             if (!token)
  282.             {  RiCreateHandle(token, RI_LIGHTSOURCE);
  283.          }
  284.             if (pointOrArea)
  285.             {  lightHandle = RiAreaLightSourceV(token, quickShader, n, tokens, parms);
  286.             }
  287.             else
  288.             {  lightHandle = RiLightSourceV(token, quickShader, n, tokens, parms);
  289.             }
  290.             break;
  291.  
  292.           default:
  293.             break;
  294.         }
  295.      }
  296.   }
  297.   else
  298.   {  
  299.      [super set];
  300.   }
  301.  
  302.   return self;
  303. }
  304.  
  305. // WWRenderable
  306.  
  307. - (BOOL)hasBoundingBox  { return NO; }
  308. - calculateBoundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime  { return self; }
  309.  
  310. - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime usingStream:(NXStream *)ns
  311. {
  312.   return self;
  313. }
  314. - renderMaps:(WW3DCamera *)camera usingStream:(NXStream *)ns
  315. {
  316.   return self;
  317. }
  318.  
  319. - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime 
  320. {
  321.   return self;
  322. }
  323. - renderMaps:(WW3DCamera *)camera
  324. {
  325.   return self;
  326. }
  327.  
  328. - setAtmosphere { volumeType = WW_ATMOSPHERE; return self; }
  329. - setInterior { volumeType = WW_INTERIOR; return self; }
  330. - setExterior { volumeType = WW_EXTERIOR; return self; }
  331. - setPointSource { pointOrArea = 0; return self; }
  332. - setAreaSource { pointOrArea = 1; return self; }
  333.  
  334. - renderSelfAsBox:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime 
  335. { return [self renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
  336.  
  337. - renderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime 
  338. {
  339.   switch ([self shaderType])
  340.   {  
  341.      case SLO_TYPE_SURFACE:
  342.        RiSurfaceV((char *)[self shader], n, tokens, parms);
  343.        break;
  344.  
  345.      case SLO_TYPE_LIGHT:
  346.        if (!token) {  RiCreateHandle(token, RI_LIGHTSOURCE); } 
  347.        if (pointOrArea)
  348.        {  lightHandle = RiAreaLightSourceV(token, (char *)[self shader], n, tokens, parms);
  349.        }
  350.        else
  351.        {  lightHandle = RiLightSourceV(token, (char *)[self shader], n, tokens, parms);
  352.        }
  353.        break;
  354.  
  355.      case SLO_TYPE_DISPLACEMENT:
  356.        RiDisplacementV((char *)[self shader], n, tokens, parms);
  357.        break;
  358.  
  359.      case SLO_TYPE_VOLUME:
  360.        switch (volumeType)
  361.        {  case WW_ATMOSPHERE:  RiAtmosphereV((char *)[self shader], n, tokens, parms);
  362.                                break;
  363.           case WW_INTERIOR:    RiInteriorV((char *)[self shader], n, tokens, parms);
  364.                                break;
  365.           case WW_EXTERIOR:    RiExteriorV((char *)[self shader], n, tokens, parms);
  366.                                break;
  367.           default:             NXLogError("unknown volume shader %s!\n", (char *)[self shader]);
  368.        }
  369.        break;
  370.  
  371.      case SLO_TYPE_TRANSFORMATION:
  372.        NXLogError("warning: using RiDeformationV for Transformation shader %s...\n", [self shader]);
  373.        RiDeformationV((char *)[self shader], n, tokens, parms);
  374.        break;
  375.  
  376.      case SLO_TYPE_IMAGER:
  377.        RiImagerV((char *)[self shader], n, tokens, parms);
  378.        break;
  379.  
  380.      default:
  381.        return nil;
  382.   }
  383.   return self;
  384. }
  385.  
  386. - renderSelf:(WW3DCamera *)camera
  387. {
  388.   RtFloat  shutterOpenTime = [camera shutterOpenTime],
  389.            shutterCloseTime = [camera shutterCloseTime];
  390.  
  391.  
  392.   return [self renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
  393. }
  394.  
  395. // this is a tough one; should the shader prerender itself?  For some shaders, especially ones
  396. // that make holes in objects, the answer is probably yes, but for those that are merely complicated
  397. // texturers, they shouldn't.  Probably best to keep a flag around to decide...
  398. // for now, just render
  399. - preRenderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime 
  400. {
  401.   return [self renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
  402. }
  403.  
  404. - preRenderSelf:(WW3DCamera *)camera 
  405. {
  406.   return [self renderSelf:camera];
  407. }
  408.  
  409. - transformCTM:(WW3DAttributeState *)attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime { return self; }
  410.  
  411. - setBoundingBox:(RtBound *)newBoundingBox { return nil; }
  412. - (RtBound *)boundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime { return (RtBound *)NULL; };
  413.  
  414. - (void)setN:(int)newN tokens:(RtToken *)newTokens parms:(RtPointer *)newParms archiveVector:(char **)newArchiveVector printfTypeVector:(int *)newPrintfTypeVector printfNVector:(int *)newPrintfNVector
  415. {  
  416.    int  i;
  417.  
  418.  
  419.    if (n)
  420.    {  for (i = 0; i < n; i++)
  421.       {  // don't free the tokens; they're shared!
  422.          free(parms[i]);
  423.          free(archiveVector[i]);
  424.          free(printfNVector);
  425.          free(printfTypeVector);
  426.       }
  427.       if (newN > n)
  428.       {  tokens = (RtToken *)NXZoneRealloc([self zone], tokens, (newN * sizeof(RtToken)));
  429.          parms = (RtPointer *)NXZoneRealloc([self zone], parms, (newN * sizeof(RtPointer)));
  430.          archiveVector = (char **)NXZoneRealloc([self zone], archiveVector, (newN * sizeof(archiveVector)));
  431.          printfNVector = (int *)NXZoneRealloc([self zone], printfNVector, (newN * sizeof(int)));
  432.          printfTypeVector = (int *)NXZoneRealloc([self zone], printfTypeVector, (newN * sizeof(int)));
  433.       }
  434.    }
  435.    else
  436.    {  tokens = (RtToken *)NXZoneMalloc([self zone], newN * sizeof(RtToken));
  437.       parms = (RtPointer *)NXZoneMalloc([self zone], newN * sizeof(RtPointer));
  438.       archiveVector = (char **)NXZoneMalloc([self zone], newN * sizeof(archiveVector));
  439.       printfNVector = (int *)NXZoneMalloc([self zone], newN * sizeof(int));
  440.       printfTypeVector = (int *)NXZoneMalloc([self zone], newN * sizeof(int));
  441.    }
  442.    n = newN;
  443.    for (i = 0; i < n; i++)
  444.    {  tokens[i] = newTokens[i];
  445.       parms[i] = newParms[i];
  446.       archiveVector[i] = newArchiveVector[i];
  447.       printfNVector[i] = newPrintfNVector[i];
  448.       printfTypeVector[i] = newPrintfTypeVector[i];
  449.    }
  450.  
  451.    return ;
  452. }
  453.  
  454. - (int)n { return n; }
  455. - (RtToken *)tokens { return tokens; }
  456. - (RtPointer *)parms { return parms; }
  457. - (char **)archiveVector { return archiveVector; }
  458. - (int *)printfNVector { return printfNVector; }
  459. - (int *)printfTypeVector { return printfTypeVector; }
  460.  
  461. // should make this lerpable, but later...
  462. - (BOOL)isLerpable { return YES; }
  463.  
  464. // this should only be called internally
  465. // the receiving object needs to copy all the parameters using the passed in zone
  466. // the assumption is that 
  467. - _mallocPointersForN:(int)newN usingZone:(NXZone *)newZone
  468. {
  469.    n = newN;
  470.    if (n)
  471.    {  tokens = (RtToken *)NXZoneMalloc([self zone], n * sizeof(RtToken));
  472.       if (!tokens)
  473.       {  return nil;
  474.       }
  475.       parms = (RtPointer *)NXZoneMalloc([self zone], n * sizeof(RtPointer));
  476.       if (!parms)
  477.       {  NXZoneFree(newZone, tokens);
  478.          return nil;
  479.       }
  480.       archiveVector = (char **)NXZoneMalloc([self zone], n * sizeof(char *));
  481.       if (!archiveVector)
  482.       {  NXZoneFree(newZone, tokens);
  483.          NXZoneFree(newZone, parms);
  484.          return nil;
  485.       }
  486.       printfNVector = (int *)NXZoneMalloc([self zone], n * sizeof(int));
  487.       if (!printfNVector)
  488.       {  NXZoneFree(newZone, tokens);
  489.          NXZoneFree(newZone, parms);
  490.          NXZoneFree(newZone, archiveVector);
  491.          return nil;
  492.       }
  493.       printfTypeVector = (int *)NXZoneMalloc([self zone], n * sizeof(int));
  494.       if (!printfTypeVector)
  495.       {  NXZoneFree(newZone, tokens);
  496.          NXZoneFree(newZone, parms);
  497.          NXZoneFree(newZone, archiveVector);
  498.          NXZoneFree(newZone, printfNVector);
  499.          return nil;
  500.       }
  501.    }
  502.    else
  503.    {  // n == 0
  504.       tokens = (RtToken *)NULL;
  505.       parms = (RtPointer *)NULL;
  506.       archiveVector = (char **)NULL;
  507.       printfNVector = (int *)NULL;
  508.       printfTypeVector = (int *)NULL;
  509.    }
  510.    return self;
  511. }
  512.  
  513. - _setToken:(char *)newToken parm:(RtPointer)newParm i:(int)i archiveInfo:(char *)archiveInfo type:(int)parmType count:(int)howMany usingZone:(NXZone *)newZone
  514. {
  515.    int  j;
  516.  
  517.  
  518.    tokens[i] = (RtToken)NXZoneMalloc(newZone, (1 + strlen(newToken)));
  519.    if (!tokens[i])
  520.    {  return nil;
  521.    }
  522.    strcpy(tokens[i], newToken);
  523.  
  524.    archiveVector[i] = (char *)NXZoneMalloc(newZone, (1 + strlen(archiveInfo)));
  525.    if (!archiveVector[i])
  526.    {  NXZoneFree(newZone, tokens[i]);
  527.       return nil;
  528.    }
  529.    strcpy(archiveVector[i], archiveInfo);
  530.  
  531.    printfTypeVector[i] = parmType;
  532.    printfNVector[i] = howMany;
  533.  
  534.    // in a perfect world, I could just copy that chunk o memory over,
  535.    // but I'm worried about alignment problems, so I'll do it the slow way...
  536.    switch (printfTypeVector[i])
  537.    {  case WW_FLOAT:  parms[i] = (RtFloat *)NXZoneMalloc(newZone, sizeof(RtFloat) * howMany); 
  538.                       for (j = 0; j < printfNVector[i]; j++)
  539.               {  *((RtFloat *)parms[i] + j) = *((RtFloat *)(newParm) + j);
  540.               }
  541.                       break;
  542.       case WW_COLOR:  parms[i] = (RtFloat *)NXZoneMalloc(newZone, sizeof(RtFloat) * howMany); 
  543.                       for (j = 0; j < printfNVector[i]; j++)
  544.               {  *((RtFloat *)parms[i] + j) = *((RtFloat *)(newParm) + j);
  545.               }
  546.                       break;
  547.       case WW_POINT:  parms[i] = (RtFloat *)NXZoneMalloc(newZone, sizeof(RtFloat) * howMany); 
  548.                       for (j = 0; j < printfNVector[i]; j++)
  549.               {  *((RtFloat *)parms[i] + j) = *((RtFloat *)(newParm) + j);
  550.               }
  551.                       break;
  552.       case WW_INT:    parms[i] = (int *)NXZoneMalloc(newZone, sizeof(int) * howMany); 
  553.                       for (j = 0; j < printfNVector[i]; j++)
  554.               {  *((int *)parms[i] + j) = *((int *)(newParm) + j);
  555.               }
  556.                       break;
  557.       // hmm, strings are weirder.  
  558.       case WW_STRING: parms[i] = (char **)NXZoneMalloc(newZone, sizeof(char *) * howMany); 
  559.                       for (j = 0; j < printfNVector[i]; j++)
  560.               {  // need to additionally malloc up some memory here, folks
  561.                          *((char **)parms[i] + j) = (char *)NXZoneMalloc(newZone, (1 + strlen(*((char **)(newParm) + j))));
  562.                          strcpy(*((char **)parms[i] + j), *((char **)(newParm) + j));
  563.               }
  564.                       break;
  565.    }      
  566.    return self;
  567. }
  568.  
  569.  
  570.  - copyFromZone:(NXZone *)newZone
  571. {
  572.   int  i;
  573.   //id   newCopy = [super copyFromZone:newZone];
  574.   id   newCopy = [(WW3DShader *)[[WW3DShader alloc] init] setShader:[self shader]];
  575.  
  576.  
  577.   // now we need to grovel over the parameters and copy them 
  578.   // this is a pain, but boy, will it be cool...
  579.   // okay, malloc up the base list of pointers
  580.   [newCopy _mallocPointersForN:n usingZone:newZone];
  581.   [newCopy setToken:[self token]];
  582.  
  583.   for (i = 0; i < n; i++)
  584.   {  if (![newCopy _setToken:tokens[i] parm:parms[i] i:i 
  585.                        archiveInfo:archiveVector[i] type:printfTypeVector[i] count:printfNVector[i] 
  586.                        usingZone:newZone])
  587.      {  [newCopy free];
  588.         return nil;
  589.      }
  590.   }
  591.   
  592.   return newCopy;
  593. }
  594.  
  595. - _lerpParametersWith:b by:(float)u
  596. {
  597.   int        i, j;
  598.   RtToken    *tokensB;
  599.   char       **archiveVectorB;
  600.   int        *printfNVectorB;
  601.   int        *printfTypeVectorB;
  602.   RtPointer  *parmsB;
  603.  
  604.  
  605.   // okay, first thing to realize is that this instance already has its 
  606.   // parameters set to the (u ==0) case here.  Therefore, when in doubt, 
  607.   // you can leave it alone and you're fine.  We now want to grovel 
  608.   // over the two objects' parameters.  
  609.   if (n != [b n])
  610.   { // hmm.  looks like trouble.  At some point, we'll have to bail,
  611.     // since the parameter lists aren't the same length.  we could
  612.     // bail right away, since we know that "self"'s parameters are set
  613.     // to something reasonable...  Yea, let's bail.
  614.     return self;
  615.   }
  616.  
  617.   tokensB = [b tokens];
  618.   archiveVectorB = [b archiveVector];
  619.   printfNVectorB = [b printfNVector];
  620.   printfTypeVectorB = [b printfTypeVector];
  621.   parmsB = [b parms];
  622.  
  623.   // okay, at this point, we know that these two objects are the same 
  624.   // class, and the length of their parameter lists are the same. Of
  625.   // course, this might be just a lucky coincidence, and the actual 
  626.   // parameters might be different types.  
  627.  
  628.   for (i = 0; i < n; i++)
  629.   {  if ((tokens[i] == tokensB[i]) || (!strcmp(tokens[i], tokensB[i])))
  630.      {  // great! they're the same token.
  631.         // now we need to make sure they're the same type and length of data
  632.         // if not, bail to the next parameter
  633.         if ((printfNVector[i] == printfNVectorB[i]) && (printfTypeVector[i] == printfTypeVectorB[i]))
  634.     {  // okay! we're golden. Let's do a lerp...
  635.            switch (printfTypeVector[i])
  636.            {  case WW_FLOAT:   for (j = 0; j < printfNVector[i]; j++)
  637.                        {  *((RtFloat *)parms[i] + j) += ((*((RtFloat *)(parmsB[i]) + j) - *((RtFloat *)parms[i] + j)) * u);
  638.                        }
  639.                                break;
  640.               case WW_COLOR:   for (j = 0; j < printfNVector[i]; j++)
  641.                        {  *((RtFloat *)parms[i] + j) += ((*((RtFloat *)(parmsB[i]) + j) - *((RtFloat *)parms[i] + j)) * u);
  642.                        }
  643.                                break;
  644.               case WW_POINT:   for (j = 0; j < printfNVector[i]; j++)
  645.                        {  *((RtFloat *)parms[i] + j) += ((*((RtFloat *)(parmsB[i]) + j) - *((RtFloat *)parms[i] + j)) * u);
  646.                        }
  647.                                break;
  648.               case WW_INT:     for (j = 0; j < printfNVector[i]; j++)
  649.                        {  *((int *)parms[i] + j) += ((*((int *)(parmsB[i]) + j) - *((int *)parms[i] + j)) * u);
  650.                    }
  651.                                break;
  652.               case WW_STRING:  // can't lerp strings without more info...
  653.                                // maybe could encode a way to do it with enumerated values, but for now, bail...
  654.                                break;
  655.            }
  656.         }
  657.         else
  658.         {  // okay, that parameter can't be lerp'ed; on to the next
  659.         }
  660.      }
  661.      else
  662.      {  // okay, that parameter can't be lerp'ed; on to the next
  663.      }
  664.   }
  665.  
  666.   // all right, we've lerped our parameters, now we need to "install" them in the shader...
  667.   for (i = 0; i < n; i++)
  668.   {  if (![self setShaderArgNamed:tokens[i] withValue:parms[i]])
  669.      {  NXLogError("in shader %s, <%s> is not a valid arg.\n", 
  670.            [self shader], tokens[i]);
  671.      }
  672.   }
  673.  
  674.   return self;
  675. }
  676.  
  677.  
  678. // note: because we've made the WWSampleList "safe" for having
  679. // multiple samples with the same data, it's perfectly valid to return
  680. // yourself or b
  681. - lerpWith:b by:(float)uValue
  682. {
  683.    id  newMe = nil;
  684.  
  685.  
  686.    if (([self class] != [b class]) || (uValue <= 0.0) || (![self shader]) || (![b shader]) || (strcmp([self shader], [b shader]))) 
  687.    {  return self;
  688.    }
  689.  
  690.    if (uValue >= 1.0)
  691.    {  return b;
  692.    }
  693.  
  694.    newMe = [self copyFromZone:[self zone]];
  695.  
  696.    // okay, now we have to get newMe to linearly interpolate it
  697.    // parameters partway between "self" and "b"
  698.    [newMe _lerpParametersWith:b by:uValue];
  699.  
  700.    return newMe;
  701. }
  702.  
  703. - lerpSelfWith:b by:(float)uValue
  704. {
  705.    if (([self class] != [b class]) || (uValue <= 0.0) || (![self shader]) || (![b shader]) || (strcmp([self shader], [b shader])))
  706.    {  return self;
  707.    }
  708.  
  709.    if (uValue >= 1.0)
  710.    {  return b;
  711.    }
  712.  
  713.    // okay, now we have to get newMe to linearly interpolate it
  714.    // parameters partway between "self" and "b"
  715.    [self _lerpParametersWith:b by:uValue];
  716.  
  717.    return self;
  718. }
  719.  
  720.  
  721. // in 3.4, shaders aren't motion blurrable
  722. - (BOOL)isMotionBlurrable { return NO; }
  723. - (BOOL)isCompoundCommand { return NO; }
  724.  
  725. // stuff for 3DReality, as well as general UI expansion
  726.  
  727. - setIconImage:image  {  iconImage = image; return self; }
  728.  
  729. - setIconImageNamed:(const char *)name
  730. {  // It's actually a bad idea to free this image, because it might be shared...
  731.    if (name && *name)
  732.    { iconImage = [NXImage findImageNamed:name];
  733.      if (!iconImage) 
  734.      {  iconImage = [[NXImage alloc] init];
  735.         // [iconImage setDataRetained:YES];
  736.         if (![iconImage loadFromFile:name])
  737.         {  NXLogError("unable to load image from file <%s>\n", name);
  738.            return nil; 
  739.      }
  740.      }    
  741.    }
  742.    return self;
  743. }
  744.  
  745. - iconImage { return iconImage; }
  746.  
  747.  
  748. // target/action messages
  749. - takeColorArg:sender
  750. {
  751.   [self setShaderArg:[sender shaderArgName] colorValue:[sender color]];
  752.   return self;
  753.  
  754. - takeFloatArg:sender
  755. {
  756.   [self setShaderArg:[sender shaderArgName] floatValue:[sender floatValue]];
  757.   return self;
  758.  
  759. - takePointArg:sender
  760. {
  761.   RtPoint  aPoint;
  762.  
  763.   N3D_XComp(aPoint) = [[sender cellAt:0 :0] floatValue];
  764.   N3D_YComp(aPoint) = [[sender cellAt:0 :1] floatValue];
  765.   N3D_ZComp(aPoint) = [[sender cellAt:0 :2] floatValue];
  766.   [self setShaderArg:[sender shaderArgName] pointValue:aPoint];
  767.   return self;
  768.  
  769. - takeStringArg:sender
  770. {
  771.   [self setShaderArg:[sender shaderArgName] stringValue:[sender stringValue]];
  772.   return self;
  773.  
  774.  
  775. // WavesWorld archiving:
  776. // writeEve:(NXStream *)stream
  777. // writeScene:(NXStream *)stream
  778.  
  779. // this is a routine for subclasses to call when archiving themselves to an eve file or a scene...
  780. - writeParameterList:(NXStream *)stream
  781. {
  782.   int  i, j;
  783.  
  784.   
  785.    if (!n)
  786.    {  NXPrintf(stream, ";");
  787.       return nil;
  788.    }
  789.    for (i = 0; i < n; i++)
  790.    {  NXPrintf(stream, "{%s} ", tokens[i]);
  791.       NXPrintf(stream, "{ ");
  792.       switch (printfTypeVector[i])
  793.       {  case WW_FLOAT:   for (j = 0; j < printfNVector[i]; j++)
  794.                       {  NXPrintf(stream, "%f ", *((RtFloat *)(parms[i]) + j));
  795.               }
  796.                           break;
  797.          case WW_COLOR:   for (j = 0; j < printfNVector[i]; j++)
  798.                        {  NXPrintf(stream, "%f ", *((RtFloat *)(parms[i]) + j));
  799.               }
  800.                           break;
  801.          case WW_POINT:   for (j = 0; j < printfNVector[i]; j++)
  802.                        {  NXPrintf(stream, "%f ", *((RtFloat *)(parms[i]) + j));
  803.               }
  804.                           break;
  805.          case WW_INT:     for (j = 0; j < printfNVector[i]; j++)
  806.                        {  NXPrintf(stream, "%d ", *((int *)(parms[i]) + j));
  807.               }
  808.                           break;
  809.          case WW_STRING:  for (j = 0; j < printfNVector[i]; j++)
  810.                        {  NXPrintf(stream, "{%s} ", *((char **)(parms[i]) + j));
  811.               }
  812.                           break;
  813.       }      
  814.       NXPrintf(stream, "} ");
  815.    }
  816.    NXPrintf(stream, ";");
  817.    return self;
  818. }
  819.  
  820. - writeEve:(NXStream *)stream atTabLevel:(int)tab
  821. {
  822.    int  i;
  823.  
  824.  
  825.    for (i = 0; i < tab; i++)
  826.    {  NXPrintf(stream, "\t");
  827.    }
  828.  
  829.    switch ([self shaderType])
  830.    {  
  831.      case SLO_TYPE_SURFACE:
  832.        NXPrintf(stream, "Surface %s ", shader); 
  833.        break;
  834.  
  835.      case SLO_TYPE_LIGHT:
  836.        if (!lightHandle)
  837.        {  lightHandleSeed++;
  838.           lightHandle = (char *)malloc(64);
  839.           sprintf(lightHandle, "%d", lightHandleSeed);
  840.        }
  841.        if (pointOrArea)
  842.        {  NXPrintf(stream, "AreaLightSource %s %s ", shader, lightHandle); 
  843.        }
  844.        else
  845.        {  NXPrintf(stream, "LightSource %s %s ", shader, lightHandle); 
  846.        }
  847.        break;
  848.  
  849.      case SLO_TYPE_DISPLACEMENT:
  850.        NXPrintf(stream, "Displacement %s ", shader); 
  851.        break;
  852.  
  853.      case SLO_TYPE_VOLUME:
  854.        switch (volumeType)
  855.        {  case WW_ATMOSPHERE:  NXPrintf(stream, "Atmosphere %s ", shader); 
  856.                                break;
  857.           case WW_INTERIOR:    NXPrintf(stream, "Interior %s ", shader); 
  858.                                break;
  859.           case WW_EXTERIOR:    NXPrintf(stream, "Exterior %s ", shader); 
  860.                                break;
  861.           default:             NXLogError("# unknown volume shader %s ", (char *)[self shader]);
  862.        }
  863.        
  864.        break;
  865.  
  866.      case SLO_TYPE_TRANSFORMATION:
  867.        NXPrintf(stream, "Deformation %s ", shader); 
  868.        break;
  869.  
  870.      case SLO_TYPE_IMAGER:
  871.        NXPrintf(stream, "Imager %s ", shader); 
  872.        break;
  873.  
  874.      default:
  875.        NXPrintf(stream, "# unknown shader %s ", shader); 
  876.        return nil;
  877.    }
  878.   
  879.    [self writeParameterList:stream];
  880.  
  881.    return self;
  882. }
  883.  
  884. - writeScene:(NXStream *)stream atTabLevel:(int)tab
  885. {
  886.    return [self writeEve:stream atTabLevel:tab];
  887. }
  888.  
  889. - write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
  890. {
  891.    int  i;
  892.  
  893.  
  894.    for (i = 0; i < tab; i++)
  895.    {  NXPrintf(stream, "\t");
  896.    }
  897.  
  898.    NXPrintf(stream, "startShape %s; ", [[self class] name]);
  899.    // need tab
  900.    // need index (position in current list)
  901.    NXPrintf(stream, 
  902.         "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n", 
  903.             tab, index); 
  904.    NXPrintf(stream, "  EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
  905.    [self writeEve:stream atTabLevel:tab];
  906.    NXPrintf(stream, "} left;}\n");
  907.   NXPrintf(stream, "endShape;\n");
  908.  
  909.   return self;
  910. }
  911.  
  912.  
  913. - writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
  914. {
  915.    int  i;
  916.  
  917.  
  918.   for (i = 0; i < tab; i++)
  919.    {  NXPrintf(stream, "\t");
  920.    }
  921.    NXPrintf(stream, "# WW3DShader %s called;", [self shader]); 
  922.    return self;
  923.  
  924. }
  925.  
  926. // NeXTSTEP archiving:
  927.  
  928. #define typeVectorVersion1 "i"
  929. #define typeValuesVersion1 &n
  930.  
  931. #define typeVector "i@"
  932. #define typeValues &n, &iconImage
  933.  
  934. - read:(NXTypedStream*)stream 
  935. {
  936.   int version, i;
  937.  
  938.  
  939.   [super read:stream];
  940.  
  941.   version = NXTypedStreamClassVersion(stream,"WW3DShader");
  942.   if (version == 0) NXReadTypes(stream,"i",&version), version=1;
  943.   if (version == 1)
  944.   {  NXReadTypes(stream, typeVectorVersion1, typeValuesVersion1);
  945.      tokens = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  946.      archiveVector = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  947.      parms = (RtPointer *)NXZoneMalloc([self zone], (sizeof(char *) * n));
  948.      for (i = 0; i < n; i++)
  949.      {  NXReadTypes(stream, "**", &(tokens[i]), &(archiveVector[i]));
  950.     NXReadTypes(stream, archiveVector[i], &(parms[i]));
  951.      }
  952.   } 
  953.   if (version == 2)
  954.   {  NXReadTypes(stream, typeVector, typeValues);
  955.      tokens = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  956.      archiveVector = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  957.      parms = (RtPointer *)NXZoneMalloc([self zone], (sizeof(char *) * n));
  958.      for (i = 0; i < n; i++)
  959.      {  NXReadTypes(stream, "**", &(tokens[i]), &(archiveVector[i]));
  960.     NXReadTypes(stream, archiveVector[i], &(parms[i]));
  961.      }
  962.   } 
  963.   if (version == 3)
  964.   {  NXReadTypes(stream, typeVector, typeValues);
  965.      tokens = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  966.      archiveVector = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  967.      parms = (RtPointer *)NXZoneMalloc([self zone], (sizeof(char *) * n));
  968.      for (i = 0; i < n; i++)
  969.      {  NXReadTypes(stream, "**", &(tokens[i]), &(archiveVector[i]));
  970.     NXReadTypes(stream, archiveVector[i], &(parms[i]));
  971.      }
  972.      NXReadTypes(stream, "*ic", &quickShader, &lightHandle, &usingSupportedQRManShader);
  973.      NXReadArray(stream, "f", 3, ribColor);
  974.   } 
  975.   if (version == 4)
  976.   {  NXReadTypes(stream, typeVector, typeValues);
  977.      tokens = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  978.      archiveVector = (char **)NXZoneMalloc([self zone], (sizeof(char *) * n));
  979.      parms = (RtPointer *)NXZoneMalloc([self zone], (sizeof(char *) * n));
  980.      for (i = 0; i < n; i++)
  981.      {  NXReadTypes(stream, "**", &(tokens[i]), &(archiveVector[i]));
  982.     NXReadTypes(stream, archiveVector[i], &(parms[i]));
  983.      }
  984.      NXReadTypes(stream, "*ic", &quickShader, &lightHandle, &usingSupportedQRManShader);
  985.      NXReadArray(stream, "f", 3, ribColor);
  986.      NXReadTypes(stream, "ic", &volumeType, &pointOrArea);
  987.   } 
  988.  
  989.   return self; 
  990. }
  991.  
  992. - write:(NXTypedStream*)stream 
  993. {
  994.   int  i;
  995.  
  996.     
  997.   [super write:stream];
  998.  
  999.   NXWriteTypes(stream,typeVector, typeValues);
  1000.   for (i = 0; i < n; i++)
  1001.   {  NXWriteTypes(stream, "**", &(tokens[i]), &(archiveVector[i]));
  1002.      NXWriteTypes(stream, archiveVector[i], &(parms[i]));
  1003.   }
  1004.   NXWriteTypes(stream, "*ic", &quickShader, &lightHandle, &usingSupportedQRManShader);
  1005.   NXWriteArray(stream, "f", 3, ribColor);
  1006.   NXWriteTypes(stream, "ic", &volumeType, &pointOrArea);
  1007.  
  1008.   return self;
  1009. }
  1010.  
  1011. // boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
  1012. - class { return [super class]; }
  1013.  
  1014. - (float)lastSampleIsAt { return 0.0; }
  1015.  
  1016. - (BOOL)isMoot
  1017. {
  1018.   return NO;
  1019. }
  1020.  
  1021. - (BOOL)isMootStartingAt:(float)startTime endingAt:(float)endTime  {  return [self isMoot];  }
  1022.  
  1023. - (BOOL)theSameAs:otherRIBCommand
  1024. {
  1025.   return NO;
  1026. }
  1027.  
  1028. - (BOOL)similarTo:otherRIBCommand 
  1029. {
  1030.   if ([self class] != [otherRIBCommand class])
  1031.   {  return NO;
  1032.   }
  1033.   return YES;
  1034. }
  1035.  
  1036.  
  1037. //WAVE FIX ME!!!
  1038. - (unsigned long int)maxSampleBandwidth { return 100; }
  1039.  
  1040. @end
  1041.