Transition effects
The Master

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.

spellcaster

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.

Ariesnl

I love crossfading ;D

Onewing

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.

spellcaster

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

#SelectExpand
1#ifndef FADE_COLLECTION_HEADER 2#define FADE_COLLECTION_HEADER 3#include "fade.h" 4 5 6// -------------------------------------------------------------------------------- 7// -- StripeFade 8// -------------------------------------------------------------------------------- 9class StripeFade : public Fade { 10 int height; 11public: 12 StripeFade(); 13 StripeFade(int h); 14 virtual ~StripeFade(); 15 virtual void fade(BITMAP* src, BITMAP* dst, double percent); 16}; 17 18// -------------------------------------------------------------------------------- 19// -- SymmetricStripeFade 20// -------------------------------------------------------------------------------- 21class SymmetricStripeFade : public Fade { 22 int height; 23public: 24 SymmetricStripeFade(); 25 SymmetricStripeFade(int h); 26 virtual ~SymmetricStripeFade(); 27 virtual void fade(BITMAP* src, BITMAP* dst, double percent); 28}; 29 30// -------------------------------------------------------------------------------- 31// -- StretchFade 32// -------------------------------------------------------------------------------- 33class StretchFade : public Fade { 34public: 35 StretchFade(); 36 virtual ~StretchFade(); 37 virtual void fade(BITMAP* src, BITMAP* dst, double percent); 38}; 39 40// -------------------------------------------------------------------------------- 41// -- ScrollFade 42// -------------------------------------------------------------------------------- 43class ScrollFade : public Fade { 44public: 45 ScrollFade(); 46 virtual ~ScrollFade(); 47 virtual void fade(BITMAP* src, BITMAP* dst, double percent); 48}; 49 50// -------------------------------------------------------------------------------- 51// -- DoorFade 52// -------------------------------------------------------------------------------- 53class DoorFade : public Fade { 54public: 55 DoorFade(); 56 virtual ~DoorFade(); 57 virtual void fade(BITMAP* src, BITMAP* dst, double percent); 58}; 59 60// -------------------------------------------------------------------------------- 61// -- BlindsFade 62// -------------------------------------------------------------------------------- 63class BlindsFade : public Fade { 64public: 65 BlindsFade(); 66 virtual ~BlindsFade(); 67 virtual void fade(BITMAP* src, BITMAP* dst, double percent); 68}; 69 70#endif

fadecol.cpp

#SelectExpand
1#include "fadecol.h" 2#include <math.h> 3 4// -------------------------------------------------------------------------------- 5// -- StripeFade 6// -------------------------------------------------------------------------------- 7StripeFade::StripeFade() : height(1) { 8} 9 10StripeFade::StripeFade(int h) : height(h) { 11} 12StripeFade::~StripeFade() { 13} 14void StripeFade::fade(BITMAP* src, BITMAP* dst, double percent) { 15 blit(src, dst, 0,0,0,0, dst->w, dst->h); 16 if (percent <= 0.5) { 17 percent *= 2; 18 int h = height*2; 19 int width = (int) (SCREEN_W * percent); 20 for (int y=0; y < SCREEN_H; y+=h) { 21 rectfill(dst, 0, y, width, y+height-1, 0); 22 } 23 } else { 24 percent -= 0.5; 25 percent *= 2; 26 int pos = SCREEN_W - (int) (SCREEN_W * percent); 27 for (int y=0; y < SCREEN_H; y+=height) { 28 rectfill(dst, 0, y, SCREEN_W, y+height-1, 0); 29 y+=height; 30 rectfill(dst, pos, y, SCREEN_W, y+height-1, 0); 31 } 32 } 33} 34 35// -------------------------------------------------------------------------------- 36// -- SymmetricStripeFade 37// -------------------------------------------------------------------------------- 38SymmetricStripeFade::SymmetricStripeFade() : height(1) { 39} 40 41SymmetricStripeFade::SymmetricStripeFade(int h) : height(h) { 42} 43SymmetricStripeFade::~SymmetricStripeFade() { 44} 45void SymmetricStripeFade::fade(BITMAP* src, BITMAP* dst, double percent) { 46 blit(src, dst, 0,0,0,0, dst->w, dst->h); 47 int w = SCREEN_W * percent; 48 for (int y=0; y < SCREEN_H; y+=height) { 49 rectfill(dst, 0, y, w, y+height-1, 0); 50 y+=height; 51 rectfill(dst, SCREEN_W-w, y, SCREEN_W, y+height-1, 0); 52 } 53} 54 55 56// -------------------------------------------------------------------------------- 57// -- StretchFade 58// -------------------------------------------------------------------------------- 59StretchFade::StretchFade() { 60} 61 62StretchFade::~StretchFade() { 63} 64void StretchFade::fade(BITMAP* src, BITMAP* dst, double percent) { 65 int w = dst->w * (1.0 - percent); 66 int h = dst->h * (1.0 - percent); 67 int x = (dst->w - w) / 2; 68 int y = (dst->h - h) / 2; 69 clear(dst); 70 stretch_blit(src, dst, 0,0,src->w, src->h, x,y, w, h); 71} 72 73 74// -------------------------------------------------------------------------------- 75// -- ScrollFade 76// -------------------------------------------------------------------------------- 77ScrollFade::ScrollFade() { 78} 79 80ScrollFade::~ScrollFade() { 81} 82void ScrollFade::fade(BITMAP* src, BITMAP* dst, double percent) { 83 int x = dst->w * percent; 84 int w = dst->w - w; 85 86 rectfill(dst, 0, 0, w, dst->h, 0); 87 blit(src, dst, 0, 0, x, 0, w, src->h); 88} 89 90// -------------------------------------------------------------------------------- 91// -- DoorFade 92// -------------------------------------------------------------------------------- 93DoorFade::DoorFade() { 94} 95 96DoorFade::~DoorFade() { 97} 98void DoorFade::fade(BITMAP* src, BITMAP* dst, double percent) { 99 int x = dst->w * percent * 0.5; 100 int w = dst->w/2 - x; 101 int x2 = src->w / 2; 102 103 blit(src, dst, x, 0, 0, 0, w, src->h); 104 blit(src, dst, x2, 0, dst->w/2+x, 0, w, src->h); 105 if (x >0) { 106 rectfill(dst, dst->w/2-x, 0, dst->w/2 +x, dst->h,0); 107 } 108} 109 110// -------------------------------------------------------------------------------- 111// -- BlindsFade 112// -------------------------------------------------------------------------------- 113BlindsFade::BlindsFade() { 114} 115 116BlindsFade::~BlindsFade() { 117} 118void BlindsFade::fade(BITMAP* src, BITMAP* dst, double percent) { 119 int h = (dst->w / 10); 120 int curH = (int) (h * percent); 121 int y = h; 122 blit(src, dst, 0, 0, 0, 0, src->w, src->h); 123 for (int a=0; a < 9; ++a) { 124 rectfill(dst, 0, y-curH, dst->w, y, 0); 125 y += h; 126 } 127}

crossfadecol.h

#SelectExpand
1#ifndef CROSSFADE_COLLECTION_HEADER 2#define CORSSFADE_COLLECTION_HEADER 3#include "crossfade.h" 4 5 6// -------------------------------------------------------------------------------- 7// -- AlphaBlending 8// -------------------------------------------------------------------------------- 9class AlphaBlending : public CrossFade { 10public: 11 AlphaBlending(); 12 virtual ~AlphaBlending(); 13 virtual void crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent); 14}; 15 16// -------------------------------------------------------------------------------- 17// -- MosaicCrossFade 18// -------------------------------------------------------------------------------- 19class MosaicCrossFade : public CrossFade { 20private: 21 int w, h; 22 BITMAP *fxBuffer; 23 BITMAP *transBuffer; 24public: 25 MosaicCrossFade(); 26 MosaicCrossFade(int w, int h); 27 virtual ~MosaicCrossFade(); 28 virtual void crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent); 29private: 30 void mosaicBlit(BITMAP *dest, BITMAP *source, unsigned int blockSize); 31}; 32 33// -------------------------------------------------------------------------------- 34// -- DoorCrossFade 35// -------------------------------------------------------------------------------- 36class DoorCrossFade : public CrossFade { 37 38public: 39 DoorCrossFade(); 40 virtual ~DoorCrossFade(); 41 virtual void crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent); 42}; 43 44// -------------------------------------------------------------------------------- 45// -- DoorZoomCrossFade 46// -------------------------------------------------------------------------------- 47class DoorZoomCrossFade : public CrossFade { 48 49public: 50 DoorZoomCrossFade(); 51 virtual ~DoorZoomCrossFade(); 52 virtual void crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent); 53}; 54 55// -------------------------------------------------------------------------------- 56// -- RollOut 57// -------------------------------------------------------------------------------- 58class RollOut : public CrossFade { 59public: 60 RollOut(); 61 virtual ~RollOut(); 62 virtual void crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent); 63}; 64#endif

crossfadecol.cpp

#SelectExpand
1#include "crossfadecol.h" 2#include <math.h> 3 4AlphaBlending::AlphaBlending() { 5} 6 7AlphaBlending::~AlphaBlending() { 8} 9 10void AlphaBlending::crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent) { 11 blit(img1, dst, 0, 0, 0, 0, img1->w, img1->h); 12 set_trans_blender(0, 0, 0, (int) (255 * percent)); 13 draw_trans_sprite(dst, img2, 0, 0); 14} 15 16MosaicCrossFade::MosaicCrossFade() : w(0), h(0), fxBuffer(NULL), transBuffer(NULL) { 17} 18 19MosaicCrossFade::MosaicCrossFade(int w, int h) { 20 this->w = w; 21 this->h = h; 22 fxBuffer = create_bitmap(w, h); 23 transBuffer = create_bitmap(w, h); 24} 25 26 27MosaicCrossFade::~MosaicCrossFade() { 28 if (fxBuffer) { 29 destroy_bitmap(fxBuffer); 30 } 31 if (transBuffer) { 32 destroy_bitmap(transBuffer); 33 } 34} 35 36void MosaicCrossFade::crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent) { 37 int bs1 = MID(1, (int) (img1->h * (1-percent)), 640); 38 int bs2 = MID(1, (int) (img2->h * percent), 640); 39 40 mosaicBlit(dst, img1, bs2); 41 mosaicBlit(transBuffer, img2, bs1); 42 set_trans_blender(0, 0, 0, (int)(255*percent)); 43 draw_trans_sprite(dst, transBuffer, 0, 0); 44} 45 46void MosaicCrossFade::mosaicBlit(BITMAP *dest, BITMAP *source, unsigned int blockSize) { 47 int dw = source->w; 48 int dh = source->h; 49 if (blockSize > 0) { 50 dw /= blockSize; 51 dh /= blockSize; 52 } 53 54 stretch_blit(source, fxBuffer, 55 0, 0, source->w, source->h, 56 0, 0, dw, dh); 57 58 stretch_blit(fxBuffer, dest, 59 0, 0, dw, dh, 60 0, 0, source->w, source->h); 61} 62 63DoorCrossFade::DoorCrossFade() { 64} 65 66DoorCrossFade::~DoorCrossFade() { 67} 68 69void DoorCrossFade::crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent) { 70 int gap = (int) (dst->w * percent); 71 int x = (int) (gap * 0.5); 72 int w = (int) (dst->w/2 - x); 73 int x2 = (int) (img1->w / 2); 74 75 blit(img2, dst, w, 0, w, 0, gap, img2->h); 76 77 blit(img1, dst, x, 0, 0, 0, w, img1->h); 78 blit(img1, dst, x2, 0, dst->w/2+x, 0, w, img1->h); 79 80} 81 82DoorZoomCrossFade::DoorZoomCrossFade() { 83} 84 85DoorZoomCrossFade::~DoorZoomCrossFade() { 86} 87 88void DoorZoomCrossFade::crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent) { 89 int gap = (int) (dst->w * percent); 90 int x = (int) (gap * 0.5); 91 int w = (int) (dst->w/2 - x); 92 int x2 = (int) (img1->w / 2); 93 94 // Berechnen der Größe des Bildes 95 int dw = (int) (img2->w * percent); 96 int dh = (int) (img2->h * percent); 97 int dx = (dst->w - dw) / 2; 98 int dy = (dst->h - dh) / 2; 99 100 if (x > 0) { 101 // Bereich löschen 102 rectfill(dst, dst->w/2-x, 0, dst->w/2 +x, dst->h,0); 103 // Anzeige in der berechneten Größe 104 stretch_blit(img2, dst, 0, 0, img2->w, img2->h, dx, dy, dw, dh); 105 } 106 107 blit(img1, dst, x, 0, 0, 0, w, img1->h); 108 blit(img1, dst, x2, 0, dst->w/2+x, 0, w, img1->h); 109 110} 111 112 113RollOut::RollOut() { 114} 115 116RollOut::~RollOut() { 117} 118 119void RollOut::crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent) { 120 121 int y = (int) (percent * img1->h); 122 int h = MIN(y, img1->h * 0.2); 123 124 blit(img2, dst, 0, 0, 0, 0, img2->w, y); 125 blit(img1, dst, 0, y+h, 0, y+h, img1->w, img1->h - y - h); 126 127 for (int a=0; a < h; a++) { 128 blit(img1, dst, 0, y+a, 0, y+h-a, img1->w, 1); 129 } 130}

crossfade.h

#ifndef CROSSFADE_HEADER
#define CROSSFADE_HEADER

#include <allegro.h>

class CrossFade {
public:    
    CrossFade();
    virtual ~CrossFade();
    virtual void crossfade(BITMAP* img1, BITMAP* img2, BITMAP* dst, double percent) = 0;
};

#endif

crossfade.cpp

#include "crossfade.h"

CrossFade::CrossFade() {
}
CrossFade::~CrossFade() {
}

fade.h

#ifndef FADE_HEADER
#define FADE_HEADER

#include <allegro.h>

class Fade {
public:    
    Fade();
    virtual ~Fade();
    virtual void fade(BITMAP* src, BITMAP* dst, double percent) = 0;
};

#endif

fade.cpp

#include "fade.h"

Fade::Fade() {
}


Fade::~Fade() {
}

miran

This posts does not exist. It is but a figment of your imagination.

spellcaster

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 
9BITMAP *doubleBuffer;
10volatile int timerCounter;
11void timerFunction(void) {
12 timerCounter++;
13}
14END_OF_FUNCTION(timerFunction);
15 
16int 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 
30BITMAP *createDoubleBuffer() {
31 BITMAP *bmp= create_bitmap(SCREEN_W, SCREEN_H);
32 return bmp;
33}
34 
35int 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 
63void done() {
64 destroy_bitmap(doubleBuffer);
65}
66 
67 
68void 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 
93void 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 
115int 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}
179END_OF_MAIN()

@Miran: Thanks!

EDIT: Changed parts of the code and removed one example. The example listed will show all effects.

Paul whoknows

I tried your examples but they crashed, I am using Dev-C++ and alleg42, also it seems sprintf is no longer available.

spellcaster

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

Paul whoknows

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! :D I am going to use the alphablending fx in my project! but I'll replace draw_trans_sprite with Fladimir's alpha blending routines.

spellcaster

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 ;))

Richard Phipps

Sounds like you needed something like Easy Allegro.. :)

The Master

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.

spellcaster

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 ;)

Thread #591493. Printed from Allegro.cc