1 /************************************************************************
2  * This file is part of Wizznic.                                        *
3  * Copyright 2009-2015 Jimmy Christensen <dusted@dusted.dk>             *
4  * Wizznic is free software: you can redistribute it and/or modify      *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation, either version 3 of the License, or    *
7  * (at your option) any later version.                                  *
8  *                                                                      *
9  * Wizznic is distributed in the hope that it will be useful,           *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
12  * GNU General Public License for more details.                         *
13  *                                                                      *
14  * You should have received a copy of the GNU General Public License    *
15  * along with Wizznic.  If not, see <http://www.gnu.org/licenses/>.     *
16  ************************************************************************/
17 
18 #include "particles.h"
19 #include "settings.h"
20 
21 #define GRAVITYCONSTANT 2
22 
23 
24 static list_t* pSystems; //All particle systems are added to this list
25 static SDL_Surface* screen;
26 
27 static psysSet_t psysPresets[PSYS_NUM_PRESETS];
28 
29 //Spawn particle system
spawnParticleSystem(psysSet_t * settings)30 void spawnParticleSystem(psysSet_t* settings)
31 {
32   if(!setting()->particles) return;
33   int i; //Gotta have a counter.
34 
35   //Create a particle system
36   pSystem_t* tSystem=malloc( sizeof(pSystem_t) );
37 
38   //Copy settings
39   tSystem->settings=(*settings);
40 
41 
42   //Setup particles
43   uint32_t col;
44   uint8_t r,g,b;
45   SDL_Surface* img;
46   //Should we use info's from a surface?
47   if(tSystem->settings.srcImg)
48   {
49     //number of particles
50     tSystem->settings.numParticles=tSystem->settings.srcRect.w*tSystem->settings.srcRect.h;
51     //Create array of particles
52     tSystem->particles = malloc( sizeof(particle_t)*(tSystem->settings.numParticles));
53     for(i=0; i<tSystem->settings.numParticles;i++)
54     {
55 
56       tSystem->particles[i].life=tSystem->settings.life - (rand()%tSystem->settings.lifeVar);
57 
58       img=tSystem->settings.srcImg;
59 
60       tSystem->particles[i].x = i%tSystem->settings.srcRect.w;
61       tSystem->particles[i].y = i/tSystem->settings.srcRect.w;
62       col=freadPixel(img,tSystem->particles[i].x+tSystem->settings.srcRect.x,tSystem->particles[i].y+tSystem->settings.srcRect.y);
63 
64       r = ((col & img->format->Rmask) >> img->format->Rshift);
65       g = ((col & img->format->Gmask) >> img->format->Gshift);
66       b = ((col & img->format->Bmask) >> img->format->Bshift);
67       if( !isAlpha(r,g,b) )
68       {
69         tSystem->particles[i].color = col;
70       } else {
71         tSystem->particles[i].color = col;
72         tSystem->particles[i].life=0;
73       }
74 
75       if(tSystem->settings.vel)
76       {
77         tSystem->particles[i].velx = (rand()%(tSystem->settings.vel*2))-(tSystem->settings.vel);
78         tSystem->particles[i].vely = (rand()%(tSystem->settings.vel*2))-(tSystem->settings.vel);
79       } else {
80         tSystem->particles[i].velx = 0;
81         tSystem->particles[i].vely = 0;
82      }
83 
84       tSystem->particles[i].x *= 100;
85       tSystem->particles[i].y *= 100;
86       tSystem->particles[i].x += tSystem->settings.x*100;
87       tSystem->particles[i].y += tSystem->settings.y*100;
88     }
89 
90   } else {
91     //Create array of particles
92     tSystem->particles = malloc( sizeof(particle_t)*(tSystem->settings.numParticles));
93 
94     for(i=0; i<tSystem->settings.numParticles;i++)
95     {
96       tSystem->particles[i].life=tSystem->settings.life - (rand()%tSystem->settings.lifeVar);
97       tSystem->particles[i].velx = (rand()%(tSystem->settings.vel*2))-(tSystem->settings.vel);
98       tSystem->particles[i].vely = (rand()%(tSystem->settings.vel*2))-(tSystem->settings.vel);
99       tSystem->particles[i].x = tSystem->settings.x*100;
100       tSystem->particles[i].y = tSystem->settings.y*100;
101 
102       if(tSystem->settings.color == PARTICLECOLORRANDOM)
103       {
104         tSystem->particles[i].color = SDL_MapRGB( screen->format, rand()%256,rand()%256,rand()%256);
105       } else {
106         tSystem->particles[i].color = tSystem->settings.color;
107       }
108     }
109   }
110 
111 
112   //Add to list of systems.
113   listAppendData(pSystems, (void*)tSystem);
114 }
115 
116 
117 //Just easier than having to deal with it down in the loop
updateParticle(particle_t * p,psysSet_t * s)118 void updateParticle(particle_t* p, psysSet_t* s)
119 {
120   //Move
121   p->x += p->velx;
122   p->y += p->vely;
123 
124   //Gravity
125   if(s->gravity)
126     p->vely += GRAVITYCONSTANT;
127   //Color?
128   //Fade?
129   //Bounce/Edge detection
130   if(p->x > (SCREENW*100) )
131   {
132     if(s->bounce)
133     {
134       p->x=(SCREENW*100);
135       p->velx *= -1;
136       p->velx -= p->velx/4; //Only lose 1/4 inertia
137     } else {
138       p->life=0;
139     }
140   }
141 
142   if(p->y > (SCREENH*100) )
143   {
144     if(s->bounce)
145     {
146       p->y=(SCREENH*100);
147       p->vely *= -1;
148       p->vely -= p->vely/3; //lose 1/3 inertia
149     } else {
150       p->life=0;
151     }
152   }
153   //Age
154   p->life -= getTicks();
155   if(p->life<0) p->life=0;
156 
157 }
158 
159 //This runs/draws all particle systems, and emitters.
runParticles(SDL_Surface * screen)160 void runParticles(SDL_Surface* screen)
161 {
162   runParticlesLayer(screen, PSYS_LAYER_TOP);
163 }
164 
165 //This will not enforce PSYS_LAYER_NODRAW (it should not, no particle systems should be created if they are not to be drawn).
runParticlesLayer(SDL_Surface * screen,int layer)166 void runParticlesLayer(SDL_Surface* screen, int layer)
167 {
168   if(!setting()->particles) return;
169 
170   pSystem_t* p; //psystem
171   int i;
172 
173   //Loop through systems
174   listItem* it = &pSystems->begin;
175   while( LISTFWD(pSystems,it) )
176   {
177     p=(pSystem_t*)it->data;
178     if(p->settings.layer==layer)
179     {
180 
181       //Draw, then update
182       for( i=0; i < p->settings.numParticles; i++ )
183       {
184         if( p->particles[i].life )
185         {
186           //Draw particle
187           plotPixel( screen, p->particles[i].x/100,p->particles[i].y/100, p->particles[i].color );
188           //Update particle
189           updateParticle(&p->particles[i], &p->settings);
190         }
191       }
192       //System life
193       p->settings.life -= getTicks();
194       if(p->settings.life<0)
195       {
196         //Remove system
197         clearSystem(p);
198         //Remove from list. (removeItem returns the item just before current, if any)
199         it=listRemoveItem(pSystems, it, LIST_PREV);
200       }
201     } //System is on correct layer
202   }
203 }
204 
205 //Frees one system
clearSystem(pSystem_t * s)206 void clearSystem(pSystem_t* s)
207 {
208   //Free particles
209   free(s->particles);
210   //Free the system
211   free(s);
212 }
213 
214 //Frees all resources and removes all systems and emitters.
clearParticles()215 void clearParticles()
216 {
217   listItem* it = &pSystems->begin;
218   //Loop through systems
219   while( LISTFWD(pSystems,it) )
220   {
221     clearSystem( (pSystem_t*)it->data );
222     it=listRemoveItem(pSystems, it, LIST_PREV);
223   }
224 }
225 
initParticles(SDL_Surface * scr)226 void initParticles(SDL_Surface* scr)
227 {
228   pSystems = listInit(NULL);
229   screen=scr;
230 
231   psysPresets[PSYS_PRESET_COLOR].layer=PSYS_LAYER_TOP;
232   psysPresets[PSYS_PRESET_COLOR].fade=0;
233   psysPresets[PSYS_PRESET_COLOR].gravity=0;
234   psysPresets[PSYS_PRESET_COLOR].bounce=0;
235   psysPresets[PSYS_PRESET_COLOR].srcImg=0;
236   psysPresets[PSYS_PRESET_COLOR].vel=100; // +/- in each dir
237   psysPresets[PSYS_PRESET_COLOR].lifeVar=10;
238   psysPresets[PSYS_PRESET_COLOR].color=PARTICLECOLORRANDOM;
239 
240   psysPresets[PSYS_PRESET_WHITE] = psysPresets[PSYS_PRESET_COLOR];
241 
242   psysPresets[PSYS_PRESET_WHITE].vel=50; // +/- in each dir
243   psysPresets[PSYS_PRESET_WHITE].color=0xFFFF;
244   psysPresets[PSYS_PRESET_WHITE].numParticles=30;
245 
246   psysPresets[PSYS_PRESET_BLACK] = psysPresets[PSYS_PRESET_WHITE];
247   psysPresets[PSYS_PRESET_BLACK].color=0x0000;
248 
249 }
250 
psysSpawnPreset(int preset,int x,int y,int num,int life)251 void psysSpawnPreset( int preset, int x, int y, int num, int life )
252 {
253   psysPresets[preset].x = x;
254   psysPresets[preset].y = y;
255   psysPresets[preset].numParticles = num;
256   psysPresets[preset].life = life;
257   spawnParticleSystem( &(psysPresets[preset]) );
258 }
259