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 | |
6 | int 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 | } |
48 | END_OF_MAIN() |
Fladimir's routines
1 | inline 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 // |
37 | inline void CallEmms() { |
38 | asm( |
39 | "emms\n" |
40 | ); |
41 | } |
42 | |
43 | |
44 | // This is a shorthand to blend single pixels at |
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.
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?
If you want to blend a whole bitmap you have to do it pixel by pixel.
Would that be faster than allegro´s blender?
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 );
Don't worry, I've also written the function for you. Here it is: (slightly edited, I hope it still works )
1 | typedef unsigned int PixelType; |
2 | |
3 | void 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 | } |
How much faster are they?
IIRC it's 300-570% faster than Allegro's alpha blender, when compiled with -O3.
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'
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
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?
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.
ah, I've just realised what you wanted
There's also FBlend.
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...?
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.
There's also FBlend.
Fblend doesn't support alpha blending.
I know it doesn't support alpha blending, but I said it as just another library to help with blending in general.
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.
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.
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.
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.
MSVC is irrelevant since he is trying to compile AT&T ASM routines, not OL itself.
Not true. At least since MSVC 7.1 support of ST
Yes True he was asking about MSVC6 and I was replying about MSVC6
Ah. I thought from your post that you were talking about MSVC in general...
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... // |
13 | inline 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 // |
49 | inline void CallEmms() { |
50 | asm( |
51 | "emms\n" |
52 | ); |
53 | } |
54 | |
55 | |
56 | // This is a shorthand to blend single pixels at a time // |
57 | inline 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 | |
72 | void 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 | |
152 | void 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 | |
225 | int 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 | } |
263 | END_OF_MAIN() |
I've attached the .o file, the source file and the bitmap which the test program uses.
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!
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!
OK, I had forgot to press the "Upload" -button... But great that it works!