Source/Particles.c

//¥ ------------------------------------------------------------------------------------------  ¥
//¥
//¥ Copyright © 1996 Apple Computer, Inc., All Rights Reserved
//¥
//¥
//¥     You may incorporate this sample code into your applications without
//¥     restriction, though the sample code has been provided "AS IS" and the
//¥     responsibility for its operation is 100% yours.  However, what you are
//¥     not permitted to do is to redistribute the source as "DSC Sample Code"
//¥     after having made changes. If you're going to re-distribute the source,
//¥     we require that you make it clear in the source that the code was
//¥     descended from Apple Sample Code, but that you've made changes.
//¥
//¥     Authors:
//¥         Chris De Salvo
//¥
//¥ ------------------------------------------------------------------------------------------  ¥
 
//¥ ------------------------------  Includes
 
#include "ErrorHandler.h"
#include "GameObject.h"
#include "MemoryHandler.h"
#include "Particles.h"
#include "SprocketInvaders.h"
 
//¥ ------------------------------  Private Definitions
 
#define kSpeckLifeTime              50
#define kSpeckLifeTimeVariance      10
 
#define kSpeckSpeedVariance         4
#define kSpeckDistanceVariance      5
 
//¥ ------------------------------  Private Types
//¥ ------------------------------  Private Variables
//¥ ------------------------------  Private Functions
 
static void SpecksInit(SpeckPtr theSpecks, SInt32 x, SInt32 y);
static SInt32 SpeckRand(SInt16 fromZero);
 
//¥ ------------------------------  Public Variables
 
//¥ --------------------    ParticlesAllocate
 
ParticlesPtr
ParticlesAllocate(SInt32 x, SInt32 y, UInt8 color)
{
ParticlesPtr    theParticles;
SpeckPtr        theSpecks;
 
    theSpecks = (SpeckPtr) NewTaggedPtrClear(sizeof (Speck) * kNumSpecks, 'SPEK', 0);
    if (! theSpecks)
        FatalError("Could not allocate particle specks.");
 
    theParticles = (ParticlesPtr) NewTaggedPtrClear(sizeof (Particles), 'PTCL', 0);
    if (! theParticles)
        FatalError("Could not allocate particles.");
 
    theParticles->numSpecks = kNumSpecks;
    theParticles->specks = theSpecks;
    theParticles->color = color;
 
    SpecksInit(theSpecks, x, y);
 
    return (theParticles);
}
 
//¥ --------------------    ParticlesDispose
 
void
ParticlesDispose(ParticlesPtr *theParticles)
{
    DisposeTaggedPtrZ((Ptr *) & (*theParticles)->specks);
    DisposeTaggedPtrZ((Ptr *) theParticles);
}
 
//¥ --------------------    ParticlesDraw
 
Rect
ParticlesDraw(ParticlesPtr theParticles, CGrafPtr dest)
{
Rect        r = { 32767, 32767, -32767, -32767 };
SpeckPtr    specks;
UInt32      i;
Rect        bounds;
UInt8       *base;
UInt32      rowBytes;
Boolean     touched;
UInt32      colorVariance;
 
    touched = false;
    specks = theParticles->specks;
    bounds = theParticles->bounds;
 
    base = (UInt8 *) GetPixBaseAddr(dest->portPixMap);
    rowBytes = (**dest->portPixMap).rowBytes & 0x3FFF;
 
    for (i = 0; i < theParticles->numSpecks; i++)
    {
        if (specks[i].age < specks[i].lifeTime)
        {
        Point   p;
        
            //¥ All the color ramps are 8-entries long going from lighter to darker.
            //¥ These two lines "age" the color of the particle so that it gets dimmer as
            //¥ it ages.  This gives the effect of an ember dying out or something.
            //¥ Anyway, I like the way it looks -- Chris
            colorVariance = specks[i].age * 8;
            colorVariance /= specks[i].lifeTime;
        
            p.h = specks[i].h;
            p.v = specks[i].v;
            
            if (PtInRect(p, &bounds))
            {
                if (p.h < r.left)
                    r.left = p.h;
                    
                if (p.h > r.right)
                    r.right = p.h;
                    
                if (p.v < r.top)
                    r.top = p.v;
                    
                if (p.v > r.bottom)
                    r.bottom = p.v;
                    
                touched = true;
                
                * (base + p.h + (p.v * rowBytes)) = theParticles->color + colorVariance;
            }
        }
    }
 
    if (! touched)
        SetRect(&r, 0, 0, 0, 0);
 
    return (r);
}
 
//¥ --------------------    SpecksInit
 
static void
SpecksInit(SpeckPtr theSpecks, SInt32 x, SInt32 y)
{
UInt32  i;
 
    for (i = 0; i < kNumSpecks; i++)
    {
    SInt32  speed;
    
        theSpecks[i].age = 0;
        theSpecks[i].lifeTime = kSpeckLifeTime + SpeckRand(kSpeckLifeTimeVariance);
        theSpecks[i].h = x + SpeckRand(kSpeckDistanceVariance);
        theSpecks[i].v = y + SpeckRand(kSpeckDistanceVariance);
        
        speed = SpeckRand(kSpeckSpeedVariance);
        if (speed < 0)
            theSpecks[i].speedH = speed;// - 1;
        else
            theSpecks[i].speedH = speed;// + 1;
            
        speed = SpeckRand(kSpeckSpeedVariance);
        if (speed < 0)
            theSpecks[i].speedV = speed;// - 1;
        else
            theSpecks[i].speedV = speed;// + 1;
    }
}
 
//¥ --------------------    SpeckRand
 
static SInt32
SpeckRand(SInt16 fromZero)
{
SInt32  theRand;
 
    theRand = Random();
    theRand *= fromZero;
    theRand /= 32767;
    
    return (theRand);
}