home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / Wave / WavesWorld / Source / IBPalettes / WW3DKit / WWSampleComponentList.m < prev    next >
Encoding:
Text File  |  1995-03-25  |  9.7 KB  |  314 lines

  1.  
  2. #import "WWSampleComponentList.h"
  3. #import "Protocol_WWRenderable.h"
  4.  
  5. @implementation WWSampleComponentList
  6.  
  7. - init
  8. {
  9.   [super init];
  10.  
  11.   timestamp = -1.;
  12.   cachedSample = [[WWSample alloc] init];
  13.   // this isn't too smart, but to avoid surprises, you could...
  14.   //[cachedSample setFreeData:NO];
  15.  
  16.   cacheIsDirty = YES;
  17.  
  18.   return self;
  19.  
  20. }
  21.  
  22. - initCount:(unsigned)numSlots
  23. {
  24.   [super initCount:numSlots];
  25.  
  26.   timestamp = -1.;
  27.   cachedSample = [[WWSample alloc] init];
  28.   // this isn't too smart, but to avoid surprises, you could...
  29.   [cachedSample setFreeData:NO];
  30.   cacheIsDirty = YES;
  31.  
  32.   return self;
  33.  
  34. }
  35.  
  36. - awake
  37. {
  38.   [super awake];
  39.  
  40.   timestamp = -1.;
  41.   cachedSample = [[WWSample alloc] init];
  42.   cacheIsDirty = YES;
  43.  
  44.   return self;
  45.  
  46. }
  47.  
  48.  
  49. - free 
  50.    //NXLogError("WWSampleComponentList %p at time %f being free'ed\n", self, timestamp);
  51.    //NXLogError("WWSample freeing cachedSample %p\n", cachedSample);
  52.    [cachedSample free];
  53.    return [super free]; 
  54. }
  55.  
  56.  
  57. - addObject_:anObject { cacheIsDirty = TRUE; return [super addObject:anObject]; }
  58.  
  59. - setData:newData timestamp:(float)floatTime generator:(const char *)genName weight:(float)floatWeight
  60. {
  61.    WWSample    *newSample, *oldSample;
  62.    BOOL        notFound;
  63.    int         i, howMany;
  64.    const char  *previousGenerator;
  65.  
  66.  
  67.    // okay, so here's the deal.  Whenever we get sent this msg, we
  68.    // first check and see if we have any data, i.e. ([self count]).  If we
  69.    // don't, we malloc up a new WWSample using this info, stick it in our
  70.    // list, set our timestamp to be this, then set the contents of our cache 
  71.    // to new sample, mark the cache clean, and return.  Actually, we should be
  72.    // lazy about it and only compute the cache as necessary...
  73.  
  74.    if (![self count])
  75.    {  timestamp = floatTime;
  76.       newSample = [[[WWSample alloc] init] setData:newData timestamp:floatTime generator:genName weight:floatWeight];
  77.       [self addObject_:newSample];
  78.    }
  79.    else
  80.    {  // need to see if we already have a sample from this source
  81.       notFound = YES;
  82.       i = 0;
  83.       howMany = [self count];
  84.  
  85.       while (notFound && (i < howMany))
  86.       {  oldSample = [self objectAt:i];
  87.          previousGenerator = [oldSample generatorName];
  88.          if (!genName)
  89.          {  if (!previousGenerator) // they're both NULL; that's it; reuse the old sample
  90.             {  [oldSample setData:newData timestamp:floatTime generator:genName weight:floatWeight];
  91.                notFound = FALSE;
  92.         }
  93.             else  // genName is NULL but this sample's not; it's not it
  94.         {}
  95.      }
  96.          else // genName isn't NULL... 
  97.          {  if (previousGenerator) // they're both not NULL; check the strings
  98.             {  if (!strcmp(genName, previousGenerator))  // same generators; that's it
  99.                {  [oldSample setData:newData timestamp:floatTime generator:genName weight:floatWeight];
  100.                   notFound = FALSE;
  101.             }
  102.                else // nope, they're not the same...
  103.                {}
  104.         }
  105.             else  // genName is NULL but this sample's not; it's not it
  106.         {}
  107.      }
  108.          i++;
  109.       }
  110.       if (notFound)
  111.       {  newSample = [[[WWSample alloc] init] setData:newData timestamp:floatTime generator:genName weight:floatWeight];
  112.          [self addObject_:newSample];
  113.       }
  114.    }
  115.    cacheIsDirty = YES; 
  116.    return self;
  117. }
  118.  
  119.  
  120. - setFreeData:(BOOL)flag
  121. {
  122.    return self;
  123. }
  124.  
  125.  
  126. - (BOOL)freeData
  127. {
  128.    return YES;
  129. }
  130.  
  131.  
  132. - (const char *)generatorName { return (const char *)NULL; }
  133.  
  134.  
  135. - addObject:(id <WWSample>)anObject 
  136.   if ([anObject conformsTo:@protocol(WWSample)])
  137.   {  cacheIsDirty = TRUE; 
  138.      return [self setData:[anObject data] timestamp:[anObject timestamp] generator:[anObject generatorName] weight:[anObject weight]];
  139.   }
  140.   NXLogError("object %s doesn't conform to the WWSample protocol: can't add it to the WWSampleComponentList", [[anObject class] name]);
  141.   return nil;
  142. }
  143.  
  144.  
  145. - insertObject:anObject at:(unsigned)index { cacheIsDirty = TRUE; return [super insertObject:anObject at:(unsigned)index]; }
  146. - removeObjectAt:(unsigned)index { cacheIsDirty = TRUE; return [super removeObjectAt:(unsigned)index]; }
  147. - removeLastObject { cacheIsDirty = TRUE; return [super removeLastObject]; }
  148. - replaceObjectAt:(unsigned)index with:newObject { cacheIsDirty = TRUE; return [super replaceObjectAt:(unsigned)index with:newObject]; }
  149. - appendList: (List *)otherList { cacheIsDirty = TRUE; return [super appendList: (List *)otherList]; }
  150. - addObjectIfAbsent:anObject { cacheIsDirty = TRUE; return [super addObjectIfAbsent:anObject]; }
  151. - removeObject:anObject  { cacheIsDirty = TRUE; return [super removeObject:anObject]; }
  152. - replaceObject:anObject with:newObject  { cacheIsDirty = TRUE; return [super replaceObject:anObject with:newObject]; }
  153. - empty  { cacheIsDirty = TRUE; timestamp = -1; return [super empty]; }
  154.  
  155. - fillCache
  156. {
  157.    int            i = 1, 
  158.                   howMany = [self count];
  159.    float          u, weightThusFar;
  160.    id <WWSample>  b = nil, 
  161.                   newData = nil;
  162.  
  163.  
  164.    if (cacheIsDirty)
  165.    {  // yow.  time to fill dat der cache...
  166.       
  167.       if (timestamp == -1)
  168.       {  // yow.  never set my timestamp
  169.          timestamp = [[self objectAt:0] timestamp];
  170.       }
  171.  
  172.       // okay, let's say we have 3 samples, the first two with weights
  173.       // of 1, and the third has a weight of 2
  174.       // a == .2, b == 3; c == 1
  175.       // so we want d = ((.2 * 1) + (3 * 1) + (1 * 2))/(1 + 1 + 2) == (.2 + 3 + 2)/4 == 5.2/4
  176.  
  177.       // can we recreate this incrementally 
  178.       // d1 = lerp between a and b
  179.       // hmm... let's take a simpler example: 1 4 4; 9/3; 3
  180.       // lerp the first two; .5 between
  181.       // lerp the result and the next; .333 
  182.  
  183.       // hmm... let's take a simpler example: 1 4 4 7; 16/4; 4
  184.       // lerp the first two; .5 between (2.5)
  185.       // lerp the result and the next; .333 ((2.5 + (1.5/3)) == 3)
  186.       // lerp the result and the next; .25 ((3 + (4/4)) == 4)
  187.  
  188.  
  189.       // copy the first element to the cache
  190.       newData = [[(WWSample *)[self objectAt:0] data] copy];
  191.       [cachedSample setData:newData timestamp:timestamp generator:"cache" weight:1.0];
  192.       weightThusFar = [[self objectAt:0] weight];
  193.       while (i < howMany)
  194.       {  b = [self objectAt:i];
  195.          //u = (1./(float)(i+1)) * ([b weight]/(weightThusFar/i));
  196.  
  197.          u = 1./((float)(i+1));  // this version of calculating u ignores weights
  198.          [[cachedSample data] lerpSelfWith:[b data] by:u];
  199.          weightThusFar += [b weight];
  200.          i++;
  201.       }
  202.    }
  203.    cacheIsDirty = NO;
  204.  
  205.    return self;
  206. }
  207.  
  208.  
  209. - (float)timestamp {  [self fillCache];  return timestamp; }
  210.  
  211. - sample  {  [self fillCache];  return cachedSample; }
  212.  
  213.  
  214. - data  {  [self fillCache];  return [cachedSample data]; }
  215.  
  216.  
  217. - setWeight:(float)newWeight  {  return self;  }
  218.  
  219.  
  220. - (float)weight  { return 1.0;  }
  221.  
  222. - (int)generatorCount { return [self count]; }
  223.  
  224. - writeEve:(NXStream *)stream atTabLevel:(int)tab
  225. {
  226.    int   howMany = [self count], 
  227.          i, j = 0;
  228.  
  229.  
  230.    //for (i = 0; i < tab; i++)
  231.    //{  NXPrintf(stream, "\t");
  232.    //}
  233.  
  234.    if (howMany)
  235.    {  if (howMany > 1)
  236.       {  [(id <WWRenderable>)[self objectAt:0] writeEve:stream atTabLevel:0];
  237.          NXPrintf(stream, " \\\n");
  238.          for (j = 1; j < (howMany-1); j++)
  239.          {  for (i = 0; i < tab; i++)
  240.             {  NXPrintf(stream, "\t");
  241.             }
  242.             for (i = 0; i < 33; i++) // magic numbers are evil, wave!!
  243.             {  NXPrintf(stream, " ");
  244.             }
  245.             [(id <WWRenderable>)[self objectAt:j] writeEve:stream atTabLevel:0];
  246.             NXPrintf(stream, " \\\n");
  247.          }
  248.          for (i = 0; i < tab; i++)
  249.          {  NXPrintf(stream, "\t");
  250.          }
  251.          for (i = 0; i < 33; i++) // magic numbers are evil, wave!!
  252.          {  NXPrintf(stream, " ");
  253.          }
  254.       }
  255.       [(id <WWRenderable>)[self objectAt:j] writeEve:stream atTabLevel:0];
  256.    }
  257.  
  258.    return self;
  259. }
  260.  
  261. - write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
  262. {
  263.    int   howMany = [self count], 
  264.          i;
  265.  
  266.  
  267.    for (i = 0; i < tab; i++)
  268.    {  NXPrintf(stream, "\t");
  269.    }
  270.  
  271.    // should look like this:
  272.    // {$owner1 {$compiledSample1}} {$owner2 {$compiledSample1}} {$owner3 {$compiledSample3}}
  273.    // so we want to actually get our samples to give us this info directly, and so I shouldn't
  274.    // recurse down calling the same routine as this.  We need a new routine... actuallly, why
  275.    // not just get the sample to write its eve code into the stream...
  276.  
  277.  
  278.    NXPrintf(stream, "startShape %s; ", [[[self objectAt:i] class] name]);
  279.    // need tab
  280.    // need index (position in current list)
  281.    NXPrintf(stream, "set __text__(colorTime%f) {1 1 1};", time);
  282.    NXPrintf(stream, "set __text__(colorSurface%f) plastic;", time);
  283.    NXPrintf(stream, "animatable: {Color $__text__(colorTime%f) }; ", time); // to make animation easy
  284.    NXPrintf(stream, "animatable: {Surface $__text__(colorSurface%f)}; ", time); // to make animation easy
  285.  
  286.    NXPrintf(stream, 
  287.         "animatable: {Translate [expr { %d * $__text__(tabLength)}] ", tab);
  288.    NXPrintf(stream, 
  289.             "[expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] ", index);
  290.    NXPrintf(stream, 
  291.             "[expr {$__text__(sampleOffset) + ($__text__(timeFactor) * %f)}]};\n", time); 
  292.    NXPrintf(stream, "  animatable: {WW3DText $__text__(fontName) $__text__(fontSize) {");
  293.  
  294.  
  295.      for (i = 0; i < howMany; i++)
  296.      {  [(id <WWRenderable>)[self objectAt:i] writeEve:stream atTabLevel:tab];
  297.         // need to be moving stuff to the left here - no, since it's one string, it will be fine......
  298.      }
  299.    NXPrintf(stream, "} left;}\n");
  300.   NXPrintf(stream, "endShape;\n");
  301.  
  302.   return self;
  303. }
  304.  
  305.  
  306.  
  307. // boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
  308. - class { return [super class]; }
  309. - (BOOL) conformsTo: (Protocol *)aProtocolObject { return [super conformsTo:aProtocolObject]; }
  310.  
  311. @end
  312.