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