hey y'all.
Anyone know algorithms for really cool screen transition effects?
I know the basic ones like fading to a color, or blocking the screen out. But what about those cool ones like how the screen blurs out like in those snes versions of super mario bros?
I'd like to kno cuz i'm doing some code for custom transition effects in an RPG and some algorithms for that would be very helpful.
Well, all transition effects are pretty similar. You have to images (i0, i1). You have transition time (t).
Now, what you want to do is to find a way that shows i0 at tcur=0 and i1 at tcur=t.
You can slide i0 in all directions out of the screen showing i1 "behind" it. You can even scroll parts i0 in different directions (one half to the left, one half to the right).
You can display lines / columns of i1 in an interval of n. Start with a large n then decrease it.
You can alpha blend the images.
You can implement a paper turn effect.
There are a lot of possibilities. Some are pretty easy to implement, some take more time.
I love crossfading
Check out the code from Ballz, a TINS game. It had several transitions when you die/finish a level. However, most transitioned to a black screen and then out from a black screen.
Here's the code I use for fading effects.
Example code will follow if somebody could reply - this post is getting too long
fadecol.h
fadecol.cpp
crossfadecol.h
crossfadecol.cpp
crossfade.h
crossfade.cpp
#include "crossfade.h" CrossFade::CrossFade() { } CrossFade::~CrossFade() { }
fade.h
fade.cpp
#include "fade.h" Fade::Fade() { } Fade::~Fade() { }
This posts does not exist. It is but a figment of your imagination.
Here's some example code:
example.cpp
1 | #include <allegro.h> |
2 | #include <stdio.h> |
3 | #include "fade.h" |
4 | #include "fadecol.h" |
5 | #include "crossfade.h" |
6 | #include "crossfadecol.h" |
7 | |
8 | |
9 | BITMAP *doubleBuffer; |
10 | volatile int timerCounter; |
11 | void timerFunction(void) { |
12 | timerCounter++; |
13 | } |
14 | END_OF_FUNCTION(timerFunction); |
15 | |
16 | int setGfxMode(int w, int h, int win) { |
17 | int mode = win ? GFX_AUTODETECT_WINDOWED : GFX_AUTODETECT_FULLSCREEN; |
18 | int colorDepth[] = {16, 15, 32, 24, 0}; |
19 | int a = 0; |
20 | while (colorDepth[a]) { |
21 | set_color_depth(colorDepth[a]); |
22 | if (set_gfx_mode(mode, w, h, 0, 0) >= 0) { |
23 | return TRUE; |
24 | } |
25 | ++a; |
26 | } |
27 | return FALSE; |
28 | } |
29 | |
30 | BITMAP *createDoubleBuffer() { |
31 | BITMAP *bmp= create_bitmap(SCREEN_W, SCREEN_H); |
32 | return bmp; |
33 | } |
34 | |
35 | int init(int preferWin) { |
36 | allegro_init(); |
37 | |
38 | /* set 640x480 hicolor preferredMode*/ |
39 | if (!setGfxMode(640, 480, preferWin)) { |
40 | /* or non preferred mode */ |
41 | if (!setGfxMode(640, 480, !preferWin)) { |
42 | return FALSE; |
43 | } |
44 | } |
45 | |
46 | /* init subsystems */ |
47 | install_keyboard(); |
48 | install_joystick(JOY_TYPE_AUTODETECT); |
49 | install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL); |
50 | install_timer(); |
51 | |
52 | /* lock timer vars / functions */ |
53 | LOCK_VARIABLE(timerCounter); |
54 | LOCK_FUNCTION(timerFunction); |
55 | |
56 | /* install logic timer */ |
57 | install_int_ex(timerFunction, BPS_TO_TIMER(60)); |
58 | |
59 | doubleBuffer = createDoubleBuffer(); |
60 | return TRUE; |
61 | } |
62 | |
63 | void done() { |
64 | destroy_bitmap(doubleBuffer); |
65 | } |
66 | |
67 | |
68 | void fade(BITMAP * from, BITMAP *to, Fade *fade, int ticks) { |
69 | double percent; |
70 | int targetTime = timerCounter + ticks; |
71 | int curTime = timerCounter; |
72 | int needsRefresh = FALSE; |
73 | |
74 | while (timerCounter < targetTime && !key[KEY_ESC]) { |
75 | if (curTime <=timerCounter) { |
76 | percent = (double) (ticks - (targetTime - curTime)) / (double) ticks; |
77 | |
78 | curTime = timerCounter+1; |
79 | needsRefresh = TRUE; |
80 | } |
81 | if (needsRefresh) { |
82 | needsRefresh = FALSE; |
83 | if (percent <= 0.5) { |
84 | fade->fade(from, doubleBuffer, percent*2.0); |
85 | } else { |
86 | fade->fade(to, doubleBuffer, 1.0 - (percent-0.5)*2.0); |
87 | } |
88 | blit(doubleBuffer, screen, 0, 0, 0, 0, doubleBuffer->w, doubleBuffer->h); |
89 | } |
90 | } |
91 | } |
92 | |
93 | void crossfade(BITMAP * from, BITMAP *to, CrossFade *fade, int ticks) { |
94 | double percent; |
95 | int targetTime = timerCounter + ticks; |
96 | int curTime = timerCounter; |
97 | int needsRefresh = FALSE; |
98 | |
99 | while (timerCounter < targetTime && !key[KEY_ESC]) { |
100 | if (curTime <=timerCounter) { |
101 | percent = (double) (ticks - (targetTime - curTime)) / (double) ticks; |
102 | |
103 | curTime = timerCounter+1; |
104 | needsRefresh = TRUE; |
105 | } |
106 | if (needsRefresh) { |
107 | needsRefresh = FALSE; |
108 | fade->crossfade(from, to, doubleBuffer, percent); |
109 | blit(doubleBuffer, screen, 0, 0, 0, 0, doubleBuffer->w, doubleBuffer->h); |
110 | } |
111 | } |
112 | } |
113 | |
114 | |
115 | int main(int argc, char** argv) { |
116 | |
117 | if (!init(argc > 1)) { |
118 | allegro_message("Unable to init"); |
119 | return 1; |
120 | } |
121 | |
122 | srand(time(NULL)); |
123 | |
124 | BITMAP *one, *two; |
125 | one = load_bitmap("image1.tga", NULL); |
126 | two = load_bitmap("image2.tga", NULL); |
127 | |
128 | if (one == NULL || two == NULL) { |
129 | allegro_message("Please place two images (image1.tga and image2.tga) in this directory"); |
130 | return 2; |
131 | } |
132 | |
133 | const int COUNT = 8; |
134 | Fade *fader[COUNT] = { |
135 | new StripeFade(10), |
136 | new StretchFade(), |
137 | new StripeFade(40), |
138 | new ScrollFade(), |
139 | new SymmetricStripeFade(20), |
140 | new DoorFade(), |
141 | new SymmetricStripeFade(4), |
142 | new BlindsFade(), |
143 | }; |
144 | |
145 | const int CROSS_FADE_COUNT = 5; |
146 | CrossFade *crossFader[CROSS_FADE_COUNT] = { |
147 | new AlphaBlending(), |
148 | new MosaicCrossFade(SCREEN_W, SCREEN_H), |
149 | new DoorCrossFade(), |
150 | new RollOut(), |
151 | new DoorZoomCrossFade(), |
152 | }; |
153 | |
154 | |
155 | int a = 0; |
156 | while (!key[KEY_ESC]) { |
157 | fade(one, two, fader[a], 90); |
158 | ++a; |
159 | a%=COUNT; |
160 | fade(two, one, fader[a], 90); |
161 | ++a; |
162 | a%=COUNT; |
163 | } |
164 | // Make sure ESC is released |
165 | while (key[KEY_ESC]); |
166 | a = 0; |
167 | while (!key[KEY_ESC]) { |
168 | crossfade(one, two, crossFader[a], 190); |
169 | ++a; |
170 | a%=CROSS_FADE_COUNT; |
171 | crossfade(two, one, crossFader[a], 190); |
172 | ++a; |
173 | a%=CROSS_FADE_COUNT; |
174 | } |
175 | |
176 | done(); |
177 | return 0; |
178 | } |
179 | END_OF_MAIN() |
@Miran: Thanks!
EDIT: Changed parts of the code and removed one example. The example listed will show all effects.
I tried your examples but they crashed, I am using Dev-C++ and alleg42, also it seems sprintf is no longer available.
Well,the crashing could be due to no images with the given name in the same directory (image1.tga, image2.tga).
Regarding sprintf: chances are that allegro no longer includes <stdio.h>. I'll add the include to the examples and I'll check if the images can be loaded.
Edit:
You can download the compiled example program and 2 example images here:
http://www.spellcaster.de/fade.zip
Yes that was the problem, I was using 2 pcx files, I did not see you were using .tga files!
Now it works nicely!
[EDIT]
Really nice! I am going to use the alphablending fx in my project! but I'll replace draw_trans_sprite with Fladimir's alpha blending routines.
Well, guess that's the problem if you simply copy'n'paste old code. I just recompiled that code with warnings enabled and almost fell out of my chair in shame.
I also realized that I can't recall all the libs and linking order to link allegro statically. Finally, it seems that this does the job:
-lalleg_s -lgdi32 -ldxguid -lole32 -ldinput -lddraw -lwinmm -ldsound
(This is the point where somebody links to the documentation showing me that this info is well documented and easily available )
Sounds like you needed something like Easy Allegro..
Those are good, but they fade from one image to another. I've got a tile based engine with sprites on top of it. What I was after was some tips on ways of postprocessing the doublebuffer, which emulates a transition effect. That is, everything gets drawn to the doublebuffer, then if the engine recieves a message to do a transition effect (from an event telling it to go to the next level or something) it will increment the effect a little.
Well, the double buffer is just an image.
Let's say your engine renders your start scene into buffer1. Let's also assume that your engine renders the second scene into buffer2. No, all you need to do is to pass these two buffers to the fade method. As you can see, it takes two BITMAPs and a percentage value.
This allows you to fade both static images or animated graphics fresh from your engine.
But I do hope you don't expect me to create a RPG engine just to demonstrate how you could fade two scenes by using the code above