/* stars.c - Starfield particle module - Don Yang (uguu.org) v0.9 (9/13/98) The butterfly movements are really lame, and I messed up the particle orientations in there somewhere... Can you fix it for me? 09/13/98: InitButterflies UninitButterflies GetAllButterflyParticles TranslateButterflies MorphButterflies GenerateButterfly */ /********************************* Header **********************************/ /* Includes */ #include #include #include #include #include"particle.h" #include"butterfl.h" /* Globals */ static BUTTERFLY _far *butterfly; static int _far *ButterflyX; static int _far *ButterflyY; static int _far *ButterflyZ; static int _far *ExtraIndexes; static int _far *ButterflyMX; static int _far *ButterflyMY; static int _far *ButterflyMZ; static int NumberOfButterflies; static int ParticlesPerButterfly, ParticlesPerWing, ExtraParticles; /* Local prototypes */ void GenerateButterfly(void); /**************************** GenerateButterfly **************************** Generate butterfly model shape. Butterfly wings generated using polar * equation: R = S * (1 + cos(A / 2)), A varies from -3*pi/4 to 3*pi/4. * In other words, a cycloid without the loop part. Butterfly body is a * stretched circle (not an ellipse!) * * IN: (global) ParticlesPerButterfly = shape distribution. * OUT: (global) ParticlesPerWing = particle distribution. * (global) (ButterflyX[], ButterflyY[], ButterflyZ[]) = coordinates. */ void GenerateButterfly(void) { int i, b; double offset, size, r, a; /* Set particle distribution */ ParticlesPerWing = ParticlesPerButterfly / 3; /* Generate right wing */ size = SPACE_W / BUTTERFLY_W_RATIO; offset = size * (1 + cos(3 * PI / 8)) + 1; for(i = 0; i < ParticlesPerWing; i++) { a = (-3 * PI / 4) + 3 * PI * i / ParticlesPerWing / 2; r = size * (1 + cos(a / 2)); ButterflyX[i] = (int)(r * cos(a) + offset); ButterflyZ[i] = (int)(r * sin(a) + offset); ButterflyY[i] = 0; } /* Generate left wing (mirrored from right wing) */ for(i = 0; i < ParticlesPerWing; i++) { ButterflyX[i + ParticlesPerWing] = -ButterflyX[i]; ButterflyY[i + ParticlesPerWing] = 0; ButterflyZ[i + ParticlesPerWing] = ButterflyZ[i]; } /* Generate body */ b = ParticlesPerButterfly - 2 * ParticlesPerWing; size = SPACE_H / BUTTERFLY_B_RATIO; for(i = 2 * ParticlesPerWing; i < ParticlesPerButterfly; i++) { a = 2 * PI * (i - (2 * ParticlesPerWing)) / b; ButterflyX[i] = 0; ButterflyY[i] = (int)(size * sin(a)); ButterflyZ[i] = (int)(size * cos(a)); } for(i = 2 * ParticlesPerWing; i < ParticlesPerButterfly; i++) { ButterflyY[i] /= 2; if( ButterflyZ[i] < 0 ) ButterflyZ[i] *= 4; ButterflyZ[i] += 2 * SPACE_W / BUTTERFLY_W_RATIO; } } /* GenerateButterfly() */ /************************ GetAllButterflyParticles ************************* Copy all particle coordinates. * * IN: (global) NumberOfButterflies = number of butterflies. * (global) ParticlesPerButterfly = shape distribution. * (global) ParticlesPerWing = particle distribution. * (global) (ButterflyX[], ButterflyY[], ButterflyZ[]) = coordinates. * (global) ExtraIndexes[] = aliases. * (global) butterfly[] = statuses. * (particle.c) NumberOfParticles = number of particles. * OUT: (particle.c) (ParticleX[], ParticleY[], ParticleZ[]) = target. */ void GetAllButterflyParticles(void) { int i, a, s; /* Copy coordinates */ for(i = 0; i < NumberOfButterflies; i++) { /* Right wing */ a = (butterfly[i].w < 0) ? (butterfly[i].w + 360) : butterfly[i].w; Rotate(ButterflyX, ButterflyY, &ParticleX[i * ParticlesPerButterfly], &ParticleY[i * ParticlesPerButterfly], ParticlesPerWing, a); /* (particle.c) */ /* Left wing */ a = 360 - a; Rotate(&ButterflyX[ParticlesPerWing], &ButterflyY[ParticlesPerWing], &ParticleX[i * ParticlesPerButterfly + ParticlesPerWing], &ParticleY[i * ParticlesPerButterfly + ParticlesPerWing], ParticlesPerWing, a); _fmemcpy(&ParticleZ[i * ParticlesPerButterfly], ButterflyZ, ParticlesPerButterfly * sizeof(int)); /* Body */ s = ParticlesPerButterfly - 2 * ParticlesPerWing; _fmemcpy(&ParticleX[i * ParticlesPerButterfly + 2 * ParticlesPerWing], &ButterflyX[2 * ParticlesPerWing], s * sizeof(int)); _fmemcpy(&ParticleY[i * ParticlesPerButterfly + 2 * ParticlesPerWing], &ButterflyY[2 * ParticlesPerWing], s * sizeof(int)); /* Transform coordinates */ Rotate(&ParticleX[i * ParticlesPerButterfly], &ParticleZ[i * ParticlesPerButterfly], &ParticleX[i * ParticlesPerButterfly], &ParticleZ[i * ParticlesPerButterfly], ParticlesPerButterfly, (butterfly[i].a + 270) % 360); for(s = i * ParticlesPerButterfly; s < (i + 1) * ParticlesPerButterfly; s++) { ParticleX[s] += butterfly[i].x; ParticleY[s] += butterfly[i].y; ParticleZ[s] += butterfly[i].z; } } /* Set leftover coordinates */ if( ExtraParticles ) { for(i = 0; i < ExtraParticles; i++) { ParticleX[NumberOfParticles - i - 1] = ParticleX[ExtraIndexes[i]]; ParticleY[NumberOfParticles - i - 1] = ParticleY[ExtraIndexes[i]]; ParticleZ[NumberOfParticles - i - 1] = ParticleZ[ExtraIndexes[i]]; } } } /* GetAllButterflyParticles() */ /****************************** InitButterflies **************************** Initialize particles. * * IN: (particles.c) NumberOfParticles = number of stars. * OUT: 0 = success. * (global) NumberOfButterflies = number of butterflies. * (global) ParticlesPerButterfly = particle distribution. * (global) ExtraParticles = undistributed particles. * (global) bufferfly[] = butterfly status. * (global) (ButterflyX[], ButterflyY[], ButterflyZ[]) = shape. * (global) (ButterflyMX[], ButterflyMY[], ButterflyMZ[]) = buf. * (global) ExtraIndexes[] = particle aliases. * 1 = not enough memory. */ int InitButterflies(void) { int i; /* Set particle counts */ NumberOfButterflies = (NumberOfParticles + BUTTERFLY_P_RATIO / 2) / BUTTERFLY_P_RATIO; if( NumberOfButterflies == 0 ) NumberOfButterflies++; ParticlesPerButterfly = NumberOfParticles / NumberOfButterflies; ExtraParticles = NumberOfParticles % ParticlesPerButterfly; /* Allocate memory */ ButterflyX = _fcalloc((size_t)ParticlesPerButterfly, sizeof(int)); ButterflyY = _fcalloc((size_t)ParticlesPerButterfly, sizeof(int)); ButterflyZ = _fcalloc((size_t)ParticlesPerButterfly, sizeof(int)); ButterflyMX = _fcalloc((size_t)NumberOfParticles, sizeof(int)); ButterflyMY = _fcalloc((size_t)NumberOfParticles, sizeof(int)); ButterflyMZ = _fcalloc((size_t)NumberOfParticles, sizeof(int)); butterfly = _fcalloc((size_t)NumberOfButterflies, sizeof(BUTTERFLY)); if( ButterflyX == NULL || ButterflyY == NULL || ButterflyZ == NULL || ButterflyMX == NULL || ButterflyMY == NULL || ButterflyMZ == NULL || butterfly == NULL ) { _ffree(ButterflyX); _ffree(ButterflyY); _ffree(ButterflyZ); _ffree(ButterflyMX); _ffree(ButterflyMY); _ffree(ButterflyMZ); _ffree(butterfly); return 1; } if( ExtraParticles ) { ExtraIndexes = _fcalloc((size_t)ExtraParticles, sizeof(int)); if( ExtraIndexes == NULL ) { _ffree(ButterflyX); _ffree(ButterflyY); _ffree(ButterflyZ); _ffree(ButterflyMX); _ffree(ButterflyMY); _ffree(ButterflyMZ); _ffree(butterfly); return 1; } } /* Generate shape coordinates */ GenerateButterfly(); /* Set index aliases */ if( ExtraParticles ) { for(i = NumberOfParticles - ExtraParticles; i < NumberOfParticles; i++) ExtraIndexes[i] = rand() % i; } /* Set initial states */ for(i = 0; i < NumberOfButterflies; i++) { butterfly[i].x = Generate(rand(), SPACE_W); butterfly[i].y = Generate(rand(), SPACE_H); butterfly[i].z = Generate(rand(), SPACE_L); butterfly[i].cx = butterfly[i].tx = butterfly[i].x; butterfly[i].cy = butterfly[i].ty = butterfly[i].y; butterfly[i].cz = butterfly[i].tz = butterfly[i].z; butterfly[i].ca = rand() % 360; butterfly[i].a = butterfly[i].ta = butterfly[i].ca; butterfly[i].frame = 0; butterfly[i].target = 1; butterfly[i].w = rand() % (BUTTERFLY_MAX_WING / 2 + 1); butterfly[i].dw = (rand() % BUTTERFLY_MAX_VW + 2) * -2; if( rand() % 2 ) { butterfly[i].w *= -1; butterfly[i].dw *= -1; } butterfly[i].state = BUTTERFLY_MOVE; } return 0; } /* InitButterflies() */ /**************************** MorphButterflies ***************************** Blend particle systems. This is where all the extra memory goes! I * just can't be bothered to morph in-place :P * * IN: frame = current morphing animation frame. * target = end animation frame. * (global) NumberOfButterflies = number of butterflies. * (global) ParticlesPerButterfly = shape distribution. * (global) ParticlesPerWing = particle distribution. * (global) (ButterflyX[], ButterflyY[], ButterflyZ[]) = coordinates. * (global) (ButterflyMX[], ButterflyMY[], ButterflyMZ[]) = morph buf. * (global) ExtraIndexes[] = aliases. * (global) butterfly[] = statuses. * (particle.c) NumberOfParticles = number of particles. * (particle.c) (ParticleX[], ParticleY[], ParticleZ[]) = source. * OUT: (particle.c) (ParticleX[], ParticleY[], ParticleZ[]) = target. */ void MorphButterflies(int frame, int target) { int i, a, s; /* Copy coordinates */ for(i = 0; i < NumberOfButterflies; i++) { /* Right wing */ a = (butterfly[i].w < 0) ? (butterfly[i].w + 360) : butterfly[i].w; Rotate(ButterflyX, ButterflyY, &ButterflyMX[i * ParticlesPerButterfly], &ButterflyMY[i * ParticlesPerButterfly], ParticlesPerWing, a); /* (particle.c) */ /* Left wing */ a = 360 - a; Rotate(&ButterflyX[ParticlesPerWing], &ButterflyY[ParticlesPerWing], &ButterflyMX[i * ParticlesPerButterfly + ParticlesPerWing], &ButterflyMY[i * ParticlesPerButterfly + ParticlesPerWing], ParticlesPerWing, a); _fmemcpy(&ButterflyMZ[i * ParticlesPerButterfly], ButterflyZ, ParticlesPerButterfly * sizeof(int)); /* Body */ s = ParticlesPerButterfly - 2 * ParticlesPerWing; _fmemcpy(&ButterflyMX[i * ParticlesPerButterfly + 2 * ParticlesPerWing], &ButterflyX[2 * ParticlesPerWing], s * sizeof(int)); _fmemcpy(&ButterflyMY[i * ParticlesPerButterfly + 2 * ParticlesPerWing], &ButterflyY[2 * ParticlesPerWing], s * sizeof(int)); /* Transform coordinates */ Rotate(&ButterflyMX[i * ParticlesPerButterfly], &ButterflyMZ[i * ParticlesPerButterfly], &ButterflyMX[i * ParticlesPerButterfly], &ButterflyMZ[i * ParticlesPerButterfly], ParticlesPerButterfly, (butterfly[i].a + 270) % 360); for(s = i * ParticlesPerButterfly; s < (i + 1) * ParticlesPerButterfly; s++) { ButterflyMX[s] += butterfly[i].x; ButterflyMY[s] += butterfly[i].y; ButterflyMZ[s] += butterfly[i].z; } } /* Set leftover coordinates */ if( ExtraParticles ) { for(i = 0; i < ExtraParticles; i++) { ButterflyMX[NumberOfParticles-i-1] = ButterflyMX[ExtraIndexes[i]]; ButterflyMY[NumberOfParticles-i-1] = ButterflyMY[ExtraIndexes[i]]; ButterflyMZ[NumberOfParticles-i-1] = ButterflyMZ[ExtraIndexes[i]]; } } /* Morph particles */ for(i = 0; i < NumberOfParticles; i++) { ParticleX[i] = Morph(ParticleX[i], ButterflyMX[i], frame, target); ParticleY[i] = Morph(ParticleY[i], ButterflyMY[i], frame, target); ParticleZ[i] = Morph(ParticleZ[i], ButterflyMZ[i], frame, target); } } /* MorphButterflies() */ /************************** TranslateButterflies *************************** Move particles. * * IN: (global) butterfly[] = butterfly status. * (particle.c) NumberOfParticles = number of particles. * OUT: (global) butterfly[] updated. */ void TranslateButterflies(void) { int i, dx, dz; for(i = 0; i < NumberOfButterflies; i++) { /* Move wings */ if( butterfly[i].state == BUTTERFLY_IDLE ) butterfly[i].w += butterfly[i].dw / 2; else butterfly[i].w += butterfly[i].dw; if( butterfly[i].w >= BUTTERFLY_MAX_WING || butterfly[i].w <= -BUTTERFLY_MAX_WING ) { butterfly[i].dw = -butterfly[i].dw; butterfly[i].w += butterfly[i].dw; } /* Move body */ if( butterfly[i].state == BUTTERFLY_MOVE ) { butterfly[i].x = Morph(butterfly[i].cx, butterfly[i].tx, butterfly[i].frame, butterfly[i].target); butterfly[i].y = Morph(butterfly[i].cy, butterfly[i].ty, butterfly[i].frame, butterfly[i].target); butterfly[i].z = Morph(butterfly[i].cz, butterfly[i].tz, butterfly[i].frame, butterfly[i].target); } else { butterfly[i].a = Morph(butterfly[i].ca, butterfly[i].ta, butterfly[i].frame, butterfly[i].target); if( butterfly[i].a < 0 ) butterfly[i].a += 360; } butterfly[i].frame++; if( butterfly[i].frame == butterfly[i].target ) { butterfly[i].frame = 0; butterfly[i].target = rand() % BUTTERFLY_ERR + BUTTERFLY_TIME; if( butterfly[i].state == BUTTERFLY_IDLE ) { butterfly[i].state = BUTTERFLY_MOVE; } else { butterfly[i].state = BUTTERFLY_IDLE; butterfly[i].cx = butterfly[i].tx; butterfly[i].cy = butterfly[i].ty; butterfly[i].cz = butterfly[i].tz; do { butterfly[i].tx = Generate(rand(), SPACE_W); butterfly[i].ty = Generate(rand(), SPACE_H); butterfly[i].tz = Generate(rand(), SPACE_L); } while( butterfly[i].tx == butterfly[i].cx || butterfly[i].ty == butterfly[i].cy || butterfly[i].tz == butterfly[i].cz ); dx = butterfly[i].tx - butterfly[i].cx; dz = butterfly[i].tz - butterfly[i].cz; butterfly[i].ca = butterfly[i].ta; butterfly[i].ta = (int)(180 * atan2(dz, dx) / PI); if( butterfly[i].ta - butterfly[i].ca > 180 ) butterfly[i].ta -= 360; } } } } /* TranslateButterflies() */ /**************************** UninitButterflies **************************** Uninitialize (reverses InitButterflies). * * IN: (global) butterfly = butterfly status. * (global) (ButterflyX[], ButterflyY[], ButterflyZ[]) = coordinates. * (global) (ButterflyMX[], ButterflyMY[], ButterflyMZ[]) = morph buf. * (global) ExtraParticles = undistributed particles. * (global) ExtraIndexes[] = particle aliases. * OUT: None. */ void UninitButterflies(void) { _ffree(ButterflyX); _ffree(ButterflyY); _ffree(ButterflyZ); _ffree(ButterflyMX); _ffree(ButterflyMY); _ffree(ButterflyMZ); _ffree(butterfly); if( ExtraParticles ) _ffree(ExtraIndexes); } /* UninitButterflies() */