Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Fladimir's alpha blending routines

Credits go to Fladimir da Gorf for helping out!
This thread is locked; no one can reply to it. rss feed Print
Fladimir's alpha blending routines
Paul whoknows
Member #5,081
September 2004
avatar

Please excuse my lack of experience but I just don't know how to use Fladimir's alpha blender, here is an example using allegro's alpha blender functions, but I can't figure out how to replace them with Fladimir's alpha blender routines.

Example

1#include <allegro.h>
2#define VIDEO_BPP 32
3#define VIDEO_W 640
4#define VIDEO_H 480
5
6int main(void)
7{
8 BITMAP *buffer;
9 BITMAP *bg;
10 BITMAP *sprite;
11 BITMAP *alpha;
12 
13 allegro_init();
14 install_keyboard();
15 install_mouse();
16
17 set_color_depth(VIDEO_BPP);
18 //set_gfx_mode(GFX_AUTODETECT, VIDEO_W, VIDEO_H, 0, 0);
19 set_gfx_mode(GFX_AUTODETECT_WINDOWED, VIDEO_W, VIDEO_H, 0, 0);
20
21 //load files
22 bg = load_bitmap("pucca.pcx", NULL);
23 sprite = load_bitmap("item.pcx", NULL);
24 alpha = load_bitmap("item_alpha.pcx", NULL);
25
26 //Write alpha blender
27 set_write_alpha_blender();
28 draw_trans_sprite(sprite, alpha, 0, 0);
29 destroy_bitmap(alpha);
30
31 //create memory buffer
32 buffer = create_bitmap(SCREEN_W, SCREEN_H);
33
34 //loop
35 while (!key[KEY_ESC])
36 {
37 blit(bg, buffer, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
38 set_alpha_blender();
39 draw_trans_sprite(buffer, sprite, mouse_x - sprite->w / 2, mouse_y - sprite->h / 2);
40 blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
41 }
42
43 show_mouse(NULL);
44 destroy_bitmap(buffer);
45 destroy_bitmap(sprite);
46 return EXIT_SUCCESS;
47}
48END_OF_MAIN()

Fladimir's routines

1inline unsigned long BlendColorsNoEmms( unsigned int dst, unsigned int src, unsigned int factor ) {
2 static unsigned short INVERT_MASK[4] = { 0x00FF, 0x00FF, 0x00FF, 0x00FF };
3 unsigned long returnParam;
4 factor = 255 - factor;
5 asm(
6 "movd %1, %%mm0\n"
7 "movd %2, %%mm1\n"
8 "pxor %%mm2, %%mm2\n"
9 "punpcklbw %%mm2, %%mm0\n"
10 "punpcklbw %%mm2, %%mm1\n"
11
12 // Get the alpha value //
13 "movd %4, %%mm3\n"
14 "punpcklwd %%mm3, %%mm3\n"
15 "punpcklwd %%mm3, %%mm3\n"
16
17 // (alpha * (source + 255 - dest))/255 + dest - alpha //
18 "paddw (%3), %%mm0\n"
19 "psubw %%mm1, %%mm0\n"
20 "psrlw $1, %%mm0\n"
21 "pmullw %%mm3, %%mm0\n"
22 "psrlw $7, %%mm0\n"
23 "paddw %%mm1, %%mm0\n"
24 "psubw %%mm3, %%mm0\n"
25
26 "packuswb %%mm0, %%mm0\n"
27 "movd %%mm0, %0\n"
28 : "=&a" (returnParam)
29 : "rm" (dst), "rm" (src), "rm" (INVERT_MASK), "rm" (factor)
30 : "memory"
31 );
32 return returnParam;
33}
34 
35 
36// ... but remember to call this one before you use any floats or doubles //
37inline void CallEmms() {
38 asm(
39 "emms\n"
40 );
41}
42 
43 
44// This is a shorthand to blend single pixels at

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Milan Mimica
Member #3,877
September 2003
avatar

BlendColorsNoEmms() is used to blend only two colors: dst and src, with factor factor. Format of the colors is RGB32, factor is [0, 255].

If you want to blend a whole bitmap you have to do it pixel by pixel.

Paul whoknows
Member #5,081
September 2004
avatar

Does that mean that I have to write my own draw_trans_sprite and set_write_alpha_blender?:'(
BTW does someone knows if Fladimir´s functions are really so fast?
How much faster are they?

Quote:

If you want to blend a whole bitmap you have to do it pixel by pixel.

Would that be faster than allegro´s blender?

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Neil Walker
Member #210
April 2000
avatar

I'm probably completely wrong here, not really using ol that much, but what you need to do is not use magic pink bitmaps, instead use graphic files with an alpha channel then call Blenders::Set( ALPHA_BLENDER );

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Fladimir da Gorf
Member #1,565
October 2001
avatar

Don't worry, I've also written the function for you. Here it is: (slightly edited, I hope it still works ;))

1typedef unsigned int PixelType;
2 
3void BasicAlphaBlend( BITMAP *src, BITMAP *dst, int dst_x, int dst_y ) {
4 ASSERT( src != 0 );
5 ASSERT( dst != 0 );
6
7 int src_x = 0;
8 int src_y = 0;
9 int w = src->w;
10 int h = src->h;
11 if( dst_x < 0 ) {
12 w += dst_x;
13 src_x -= dst_x;
14 dst_x = 0;
15 }
16 if( dst_y < 0 ) {
17 h += dst_y;
18 src_y -= dst_y;
19 dst_y = 0;
20 }
21 if( dst_x + w > dst->w ) {
22 w -= dst_x + w - dst->w;
23 }
24 if( w <= 0 ) return;
25 if( dst_y + h > dst->h ) {
26 h -= dst_y + h - dst->h;
27 }
28 if( h <= 0 ) return;
29
30 for( int j = 0; j < h; j++ ) {
31 PixelType *src_ptr = ((PixelType *)src->line[src_y+j]) + src_x;
32 PixelType *dst_ptr = ((PixelType *)dst->line[dst_y+j]) + dst_x;
33 for( int i = 0; i < w; i++ ) {
34 unsigned char fact = geta32( *src_ptr );
35
36 if( fact != 0 ) {
37 if( fact == 255 ) *dst_ptr = *src_ptr;
38 else *dst_ptr = BlendColorsNoEmms( *dst_ptr, *src_ptr, fact );
39 }
40 src_ptr++;
41 dst_ptr++;
42 }
43 }
44
45 CallEmms();
46}

Quote:

How much faster are they?

IIRC it's 300-570% faster than Allegro's alpha blender, when compiled with -O3.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Paul whoknows
Member #5,081
September 2004
avatar

Wow! thank you very very much!:D
What compiler are you using?
I am using MSVC6 and I have some problems with the assembler lines inside your functions.
MSVC6 uses __asm {}, instead of asm(), I replaced that and other microsoft specific stuffs but still it doesn't compile, I don't know what is wrong here.
I get multiple errors like this
C2400: in-line assembler syntax error in 'opcode'; found 'bad token'

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

HoHo
Member #4,534
April 2004
avatar

He uses gcc style for ASM (I can't remember the correct name). To make it work with MSVC you would have to rewrite the whole ASM stuff with Intel syntax. In other words, if you don't know ASM then use GCC :)

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Fladimir da Gorf
Member #1,565
October 2001
avatar

Maybe switching the opcode parameters would be sufficient?

For example, "movd %2, %%mm1\n" becomes "movd %%mm1, %2\n"

Though I also think that you'll also need to remove one % from them.

Is it possible to compile the source with GCC and then import the object file in a MSVC project?

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Milan Mimica
Member #3,877
September 2003
avatar

Quote:

Is it possible to compile the source with GCC and then import the object file in a MSVC project?

Allegro does something like that in the build process.

Neil Walker
Member #210
April 2000
avatar

ah, I've just realised what you wanted :)

There's also FBlend.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Edward Sheets
Member #4,734
June 2004
avatar

Any chance Flad's blender could be incorporated into Allegro? Seems like a speed increase of that magnitude would be well worth it.

Fblend is sweet but I don't think it's been worked on in a while and it has some bugs. I seem to remember there being a problem with running it on 64-bit processors...?

---

Note: carving a pentagram on the top of a container of spoiled yogurt does not summon a yogurt demon. -Kikaru

Paul whoknows
Member #5,081
September 2004
avatar

Quote:

Maybe switching the opcode parameters would be sufficient?

I tried that, but it didn't work, I'll try to download GCC later and compile your routines to obtain the .obj as you said, I really want to include your routines in my game, but right now I am really busy trying to solve a lot of problems with the game programming itself.
I didn't know that the AT&T and Intel syntaxes were so difficult to translate between each other.

Quote:

There's also FBlend.

Fblend doesn't support alpha blending.

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Neil Walker
Member #210
April 2000
avatar

I know it doesn't support alpha blending, but I said it as just another library to help with blending in general.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Paul whoknows
Member #5,081
September 2004
avatar

Quote:

Is it possible to compile the source with GCC and then import the object file in a MSVC project?

Can someone compile Fladimir's alpha blend routines and give me the .obj so I can use them in MSVC6?
My dial-up connection dosen't allow me to download the GCC compiler right now:-/
Thanks in advance.

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

HoHo
Member #4,534
April 2004
avatar

http://www.bloodshed.net/dev/devcpp.html

Dev-cpp with GCC 3.4.2 is around 9.2MiB or half an hour with good dial-up connection. If noone else has time or willing to compile it for you then that might help you. I might help you myself but unfortunately I don't have Windows.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Neil Walker
Member #210
April 2000
avatar

The best minds in the world have tried to compile OL with MSVC but it fails due to MSVC's support of the STL and other related issues.

As hoho, get devcpp, or the free msvc8 (negating the need to have msvc6), mingw, code:blocks, etc.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

tobing
Member #5,213
November 2004
avatar

Quote:

The best minds in the world have tried to compile OL with MSVC but it fails due to MSVC's support of the STL and other related issues.

Not true. At least since MSVC 7.1 support of STL 'and other related issues' are good enough to compile OpenLayer. Version 6.0 of MSVC does not work well though.

HoHo
Member #4,534
April 2004
avatar

MSVC is irrelevant since he is trying to compile AT&T ASM routines, not OL itself.

__________
In theory, there is no difference between theory and practice. But, in practice, there is - Jan L.A. van de Snepscheut
MMORPG's...Many Men Online Role Playing Girls - Radagar
"Is Java REALLY slower? Does STL really bloat your exes? Find out with your friendly host, HoHo, and his benchmarking machine!" - Jakub Wasilewski

Neil Walker
Member #210
April 2000
avatar

Quote:

Not true. At least since MSVC 7.1 support of ST

Yes True ;) he was asking about MSVC6 and I was replying about MSVC6 :)

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

tobing
Member #5,213
November 2004
avatar

Ah. I thought from your post that you were talking about MSVC in general...

Fladimir da Gorf
Member #1,565
October 2001
avatar

I actually found my old sources from my hard drive, here's the complete source:

1#include <allegro.h>
2#include <loadpng.h>
3 
4 
5/*
6 * BlendColors32 by Esa Tanskanen
7 * Fast 32-bit color mixing routines
8 * Use the BlendColors32 function if unsure
9 */
10
11
12// If you wish to process multiple pixels at once, use this function... //
13inline unsigned long BlendColors32NoEmms( unsigned long dst, unsigned long src, unsigned long factor ) {
14 static unsigned short INVERT_MASK[4] = { 0x00FF, 0x00FF, 0x00FF, 0x00FF };
15 unsigned long returnParam;
16 factor = 255 - factor;
17 asm(
18 "movd %1, %%mm0\n"
19 "movd %2, %%mm1\n"
20 "pxor %%mm2, %%mm2\n"
21 "punpcklbw %%mm2, %%mm0\n"
22 "punpcklbw %%mm2, %%mm1\n"
23
24 // Get the alpha value //
25 "movd %4, %%mm3\n"
26 "punpcklwd %%mm3, %%mm3\n"
27 "punpcklwd %%mm3, %%mm3\n"
28
29 // (alpha * (source + 255 - dest))/255 + dest - alpha //
30 "paddw (%3), %%mm0\n"
31 "psubw %%mm1, %%mm0\n"
32 "psrlw $1, %%mm0\n"
33 "pmullw %%mm3, %%mm0\n"
34 "psrlw $7, %%mm0\n"
35 "paddw %%mm1, %%mm0\n"
36 "psubw %%mm3, %%mm0\n"
37
38 "packuswb %%mm0, %%mm0\n"
39 "movd %%mm0, %0\n"
40 : "=&a" (returnParam)
41 : "rm" (dst), "rm" (src), "rm" (INVERT_MASK), "rm" (factor)
42 : "memory"
43 );
44 return returnParam;
45}
46 
47 
48// ... but remember to call this one before you use any floats or doubles //
49inline void CallEmms() {
50 asm(
51 "emms\n"
52 );
53}
54 
55 
56// This is a shorthand to blend single pixels at a time //
57inline unsigned long BlendColors32( unsigned long dst, unsigned long src, unsigned long factor ) {
58 unsigned long returnParam = BlendColors32NoEmms( dst, src, factor );
59 CallEmms();
60 return returnParam;
61}
62 
63 
64 
65/*
66 * AlphaBlend32 by Esa Tanskanen
67 * 32-bit alpha blending routines with a global alpha value
68 * Notice that the source bitmap comes before the destination bitmap!
69 */
70 
71 
72void AlphaBlend32( BITMAP *src, BITMAP *dst, int dst_x, int dst_y, int globalAlpha ) {
73 /* The following conditions must be true */
74 ASSERT( src );
75 ASSERT( dst );
76 ASSERT( bitmap_color_depth( src ) == 32 );
77 ASSERT( bitmap_color_depth( dst ) == 32 );
78
79 /* Apply clipping */
80 int src_x = 0;
81 int src_y = 0;
82 int w = src->w;
83 int h = src->h;
84
85 if( dst_x < 0 ) {
86 w += dst_x;
87 src_x -= dst_x;
88 dst_x = 0;
89 }
90
91 if( dst_y < 0 ) {
92 h += dst_y;
93 src_y -= dst_y;
94 dst_y = 0;
95 }
96
97 if( dst_x + w > dst->w ) {
98 w -= dst_x + w - dst->w;
99 }
100
101 if( w <= 0 ) return;
102
103 if( dst_y + h > dst->h ) {
104 h -= dst_y + h - dst->h;
105 }
106
107 if( h <= 0 ) return;
108
109 /* Select destination surface for reading and writing */
110 acquire_bitmap( dst );
111 bmp_select( dst );
112
113 /* Loop through all pixels */
114 for( int j = 0; j < h; j++ ) {
115 unsigned int *src_ptr = ((unsigned int *)src->line[src_y+j]) + src_x;
116 unsigned int dst_address = bmp_write_line( dst, dst_y+j ) + 4*dst_x;
117
118 for( int i = 0; i < w; i++ ) {
119 unsigned int srcColor = *src_ptr;
120 /* Extract the alpha value */
121 unsigned int fact = ( geta32( srcColor ) * globalAlpha ) >> 8;
122
123 /* Blend the colors if required */
124 if( fact != 0 ) {
125 if( fact >= 255 ) bmp_write32( dst_address, srcColor );
126 else bmp_write32( dst_address, BlendColors32NoEmms( *((unsigned int *) dst_address), *src_ptr, fact ));
127 }
128
129 /* Advance to the next pixel */
130 dst_address += 4;
131 src_ptr++;
132 }
133 }
134
135 /* Finish blending */
136 CallEmms();
137
138 /* Finish messing with the destination bitmap */
139 bmp_unwrite_line( dst );
140 release_bitmap( dst );
141}
142 
143 
144 
145/*
146 * AlphaBlend32 by Esa Tanskanen
147 * 32-bit alpha blending routines
148 * Notice that the source bitmap comes before the destination bitmap!
149 */
150 
151 
152void AlphaBlend32( BITMAP *src, BITMAP *dst, int dst_x, int dst_y ) {
153 /* The following conditions must be true */
154 ASSERT( src );
155 ASSERT( dst );
156 ASSERT( bitmap_color_depth( src ) == 32 );
157 ASSERT( bitmap_color_depth( dst ) == 32 );
158
159 /* Apply clipping */
160 int src_x = 0;
161 int src_y = 0;
162 int w = src->w;
163 int h = src->h;
164
165 if( dst_x < 0 ) {
166 w += dst_x;
167 src_x -= dst_x;
168 dst_x = 0;
169 }
170
171 if( dst_y < 0 ) {
172 h += dst_y;
173 src_y -= dst_y;
174 dst_y = 0;
175 }
176
177 if( dst_x + w > dst->w ) {
178 w -= dst_x + w - dst->w;
179 }
180
181 if( w <= 0 ) return;
182
183 if( dst_y + h > dst->h ) {
184 h -= dst_y + h - dst->h;
185 }
186
187 if( h <= 0 ) return;
188
189 /* Select destination surface for reading and writing */
190 acquire_bitmap( dst );
191 bmp_select( dst );
192
193 /* Loop through all pixels */
194 for( int j = 0; j < h; j++ ) {
195 unsigned int *src_ptr = ((unsigned int *)src->line[src_y+j]) + src_x;
196 unsigned int dst_address = bmp_write_line( dst, dst_y+j ) + 4*dst_x;
197
198 for( int i = 0; i < w; i++ ) {
199 unsigned int srcColor = *src_ptr;
200 /* Extract the alpha value */
201 unsigned int fact = geta32( srcColor );
202
203 /* Blend the colors if required */
204 if( fact != 0 ) {
205 if( fact >= 255 ) bmp_write32( dst_address, srcColor );
206 else bmp_write32( dst_address, BlendColors32NoEmms( *((unsigned int *) dst_address), *src_ptr, fact ));
207 }
208
209 /* Advance to the next pixel */
210 dst_address += 4;
211 src_ptr++;
212 }
213 }
214
215 /* Finish blending */
216 CallEmms();
217
218 /* Finish messing with the destination bitmap */
219 bmp_unwrite_line( dst );
220 release_bitmap( dst );
221}
222 
223 
224 
225int main() {
226 /* Setup Allegro */
227 allegro_init();
228 install_keyboard();
229
230 set_color_depth( 32 );
231 set_gfx_mode( GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0 );
232
233 BITMAP *buffer = create_bitmap( SCREEN_W, SCREEN_H );
234
235 /* mybmp.png must be a 32-bit bitmap with an alpha channel! */
236 BITMAP *sprite = load_png( "mybitmap.png", 0 );
237
238 /* Draw it to the buffer */
239 AlphaBlend32( sprite, buffer, 0, 100 );
240
241 /* Draw it 3 times to the buffer with different apha values */
242 AlphaBlend32( sprite, buffer, 100 , 100, 255 );
243 AlphaBlend32( sprite, buffer, 100 + sprite->w, 100, 150 );
244 AlphaBlend32( sprite, buffer, 100 + 2*sprite->w, 100, 50 );
245
246 blit( buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H );
247
248 readkey();
249
250 /* You can also draw directly to the screen, but that's not recommended
251 as it's much slower */
252
253 AlphaBlend32( sprite, screen, 0, 100 + sprite->h );
254
255 AlphaBlend32( sprite, screen, 100 , 100 + sprite->h, 255 );
256 AlphaBlend32( sprite, screen, 100 + sprite->w, 100 + sprite->h, 150 );
257 AlphaBlend32( sprite, screen, 100 + 2*sprite->w, 100 + sprite->h, 50 );
258
259 readkey();
260
261 return 0;
262}
263END_OF_MAIN()

I've attached the .o file, the source file and the bitmap which the test program uses.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Paul whoknows
Member #5,081
September 2004
avatar

Quote:

I've attached the .o file, the source file and the bitmap which the test program uses.

I can't download your attachment, I can't see it, can you check your attachment please?, and thanks again for all your help I really appreciate it!

Quote:

Dev-cpp with GCC 3.4.2 is around 9.2MiB or half an hour with good dial-up connection

What! only 9MB?, I only knew the official GCC site and it was very intimidating, I did not know about the link you posted, I'll download it right now!

[EDIT]

I followed Hoho's advice, Devcpp makes everything so nice and easy, specially after a long time using MSVC6!
Fladimir eveything works perfectly now! thank you very much, you gave me a lot of help and I'll add your name in the credits!

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Fladimir da Gorf
Member #1,565
October 2001
avatar

OK, I had forgot to press the "Upload" -button... But great that it works!

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Go to: