Control: Change controls to use new callback infrastrucure.
[gemrb.git] / gemrb / core / Particles.cpp
bloba89b2edabbeb03617217337c0b4ffbc7da34361b
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2006 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program 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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "Particles.h"
23 #include "Interface.h"
24 #include "Video.h"
26 Color sparkcolors[MAX_SPARK_COLOR][MAX_SPARK_PHASE];
27 bool inited = false;
29 void TranslateColor(const char *value, Color &color)
31 int r = 0;
32 int g = 0;
33 int b = 0;
34 //if not RGB then try to interpret it as a dword
35 if (strnicmp(value,"RGB(",4)) {
36 r = strtol(value,NULL,0);
37 color.r = r&0xff;
38 color.g = (r>>8)&0xff;
39 color.b = (r>>16)&0xff;
40 color.a = (r>>24)&0xff;
42 sscanf(value+4,"%d,%d,%d)", &r, &g, &b);
43 color.r=r;
44 color.g=g;
45 color.b=b;
48 void InitSparks()
50 int i,j;
51 AutoTable tab("sprklclr");
52 if (!tab)
53 return;
55 memset(sparkcolors,0,sizeof(sparkcolors));
56 for (i=0;i<MAX_SPARK_COLOR;i++) {
57 for (j=0;j<MAX_SPARK_PHASE;j++) {
58 sparkcolors[i][j].a=0xff;
61 i = tab->GetRowCount();
62 if (i>MAX_SPARK_COLOR) {
63 i = MAX_SPARK_COLOR;
65 while (i--) {
66 for (int j=0;j<MAX_SPARK_PHASE;j++) {
67 //not filling the first entry
68 const char *value = tab->QueryField(i,j);
69 TranslateColor(value, sparkcolors[i+1][j]);
74 Particles::Particles(int s)
76 points = (Element *) malloc(s*sizeof(Element) );
77 memset(points, -1, s*sizeof(Element) );
79 for (int i=0;i<MAX_SPARK_PHASE;i++) {
80 bitmap[i]=NULL;
83 fragments = NULL;
84 if (!inited) {
85 InitSparks();
87 size = last_insert = s;
88 color = 0;
89 phase = P_FADE;
90 owner = NULL;
91 type = SP_TYPE_POINT;
92 path = SP_PATH_FALL;
93 spawn_type = SP_SPAWN_NONE;
96 Particles::~Particles()
98 if (points) {
99 free(points);
102 for (int i=0;i<MAX_SPARK_PHASE;i++) {
103 delete( bitmap[i]);
106 delete fragments;
109 void Particles::SetBitmap(unsigned int FragAnimID)
111 //int i;
113 delete fragments;
115 fragments = new CharAnimations(FragAnimID, 0);
117 for (i=0;i<MAX_SPARK_PHASE;i++) {
118 delete( bitmap[i] );
121 AnimationFactory* af = ( AnimationFactory* )
122 gamedata->GetFactoryResource( BAM, IE_BAM_CLASS_ID );
124 if (af == NULL) {
125 return;
128 for (i=0;i<MAX_SPARK_PHASE; i++) {
129 bitmap[i] = af->GetCycle( i );
135 bool Particles::AddNew(const Point &point)
137 int st;
139 switch(path)
141 case SP_PATH_EXPL:
142 st = (last_insert%15)<<16;
143 break;
144 case SP_PATH_RAIN:
145 case SP_PATH_FLIT:
146 st = core->Roll(3,5,MAX_SPARK_PHASE)<<4;
147 break;
148 case SP_PATH_FOUNT:
149 st =(MAX_SPARK_PHASE + 2*pos.h)<<4;
150 break;
151 case SP_PATH_FALL:
152 default:
153 st =(MAX_SPARK_PHASE + pos.h)<<4;
154 break;
156 int i = last_insert;
157 while (i--) {
158 if (points[i].state == -1) {
159 points[i].state = st;
160 points[i].pos = point;
161 last_insert = i;
162 return false;
165 i = size;
166 while (i--!=last_insert) {
167 if (points[i].state == -1) {
168 points[i].state = st;
169 points[i].pos = point;
170 last_insert = i;
171 return false;
174 return true;
177 void Particles::Draw(const Region &screen)
179 int length; //used only for raindrops
181 Video *video=core->GetVideoDriver();
182 Region region = video->GetViewport();
183 if (owner) {
184 region.x-=pos.x;
185 region.y-=pos.y;
187 int i = size;
188 while (i--) {
189 if (points[i].state == -1) {
190 continue;
192 int state = points[i].state>>4;
193 if (state>=MAX_SPARK_PHASE) {
194 length = 6-abs(state-MAX_SPARK_PHASE-6);
195 state = 0;
196 } else {
197 state=MAX_SPARK_PHASE-state;
198 length=0;
200 Color clr = sparkcolors[color][state];
201 switch (type) {
202 case SP_TYPE_BITMAP:
204 if (bitmap[state]) {
205 Sprite2D *frame = bitmap[state]->GetFrame(points[i].state&255);
206 video->BlitGameSprite(frame,
207 points[i].pos.x+screen.x,
208 points[i].pos.y+screen.y, 0, clr,
209 NULL, NULL, &screen);
212 if (fragments) {
213 //IE_ANI_CAST stance has a simple looping animation
214 Animation** anims = fragments->GetAnimation( IE_ANI_CAST, i );
215 if (anims) {
216 Animation* anim = anims[0];
217 Sprite2D* nextFrame = anim->GetFrame(anim->GetCurrentFrame());
218 video->BlitGameSprite( nextFrame, points[i].pos.x - region.x, points[i].pos.y - region.y,
219 0, clr, NULL, fragments->GetPartPalette(0), &screen);
222 break;
223 case SP_TYPE_CIRCLE:
224 video->DrawCircle (points[i].pos.x-region.x,
225 points[i].pos.y-region.y, 2, clr, true);
226 break;
227 case SP_TYPE_POINT:
228 default:
229 video->SetPixel (points[i].pos.x-region.x,
230 points[i].pos.y-region.y, clr, true);
231 break;
232 case SP_TYPE_LINE: // this is more like a raindrop
233 if (length) {
234 video->DrawLine (points[i].pos.x+region.x,
235 points[i].pos.y+region.y,
236 points[i].pos.x+region.x+(i&1),
237 points[i].pos.y+region.y+length, clr, true);
239 break;
244 void Particles::AddParticles(int count)
246 while (count--) {
247 Point p;
249 switch (path) {
250 case SP_PATH_EXPL:
251 p.x = pos.w/2;
252 p.y = pos.h/2;
253 break;
254 case SP_PATH_FALL:
255 default:
256 p.x = core->Roll(1,pos.w,0);
257 p.y = core->Roll(1,pos.h/2,0);
258 break;
259 case SP_PATH_RAIN:
260 case SP_PATH_FLIT:
261 p.x = core->Roll(1,pos.w,0);
262 p.y = core->Roll(1,pos.h,0);
263 break;
264 case SP_PATH_FOUNT:
265 p.x = core->Roll(1,pos.w/2,pos.w/4);
266 p.y = core->Roll(1,pos.h/2,0);
267 break;
269 if (AddNew(p) ) {
270 break;
275 int Particles::Update()
277 int drawn=false;
278 int i;
279 int grow;
281 if (phase==P_EMPTY) {
282 return drawn;
285 switch(spawn_type) {
286 case SP_SPAWN_NONE:
287 grow = 0;
288 break;
289 case SP_SPAWN_FULL:
290 grow = size;
291 spawn_type=SP_SPAWN_NONE;
292 break;
293 case SP_SPAWN_SOME:
294 default:
295 grow = size/10;
297 for(i=0;i<size;i++) {
298 if (points[i].state==-1) {
299 continue;
301 drawn=true;
302 if (!points[i].state) {
303 grow++;
305 points[i].state--;
307 switch (path) {
308 case SP_PATH_FALL:
309 points[i].pos.y+=3+((i>>2)&3);
310 points[i].pos.y%=pos.h;
311 break;
312 case SP_PATH_RAIN:
313 points[i].pos.x+=pos.w+(i&1);
314 points[i].pos.x%=pos.w;
315 points[i].pos.y+=3+((i>>2)&3);
316 points[i].pos.y%=pos.h;
317 break;
318 case SP_PATH_FLIT:
319 if (points[i].state<=MAX_SPARK_PHASE<<4) {
320 break;
322 points[i].pos.x+=core->Roll(1,3,pos.w-2);
323 points[i].pos.x%=pos.w;
324 points[i].pos.y+=(i&3)+1;
325 break;
326 case SP_PATH_FOUNT:
327 if (points[i].state<=MAX_SPARK_PHASE<<4) {
328 break;
330 if (points[i].state>(MAX_SPARK_PHASE<<4)+pos.h) {
331 if ( (points[i].state&7) == 7) {
332 points[i].pos.x+=(i&3)-1;
334 points[i].pos.y++;
335 } else {
336 if ( (points[i].state&7) == 7) {
337 points[i].pos.x+=(i&3)-1;
339 points[i].pos.y--;
341 break;
344 if (phase==P_GROW) {
345 AddParticles(grow);
346 drawn=true;
348 if (!drawn) {
349 phase = P_EMPTY;
351 return drawn;