1/*         ______   ___    ___
2 *        /\  _  \ /\_ \  /\_ \
3 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 *                                           /\____/
9 *                                           \_/__/
10 *
11 *      Helper macros for constructing the asm sprite drawing routines.
12 *
13 *      By Shawn Hargreaves.
14 *
15 *      See readme.txt for copyright information.
16 */
17
18
19#ifndef ALLEGRO_I386_SPRITE_INC
20#define ALLEGRO_I386_SPRITE_INC
21
22
23
24/* generic framework for constructing sprite drawing routines, shared
25 * between the 8, 16, 24, and 32 bit versions of the code...
26 */
27
28
29#define S_BMP       ARG1
30#define S_SPRITE    ARG2
31#define S_X         ARG3
32#define S_Y         ARG4
33
34#define S_TGAP   -4(%ebp)
35#define S_LGAP   -8(%ebp)
36#define S_SGAP   -12(%ebp)
37#define S_W      -16(%ebp)
38#define S_H      -20(%ebp)
39#define S_C      -24(%ebp)
40#define S_MASK   -28(%ebp)
41
42
43
44/* sets up a sprite draw operation and handles the clipping */
45#define START_SPRITE_DRAW(name)                                              \
46   pushl %ebp                                                              ; \
47   movl %esp, %ebp                                                         ; \
48   subl $28, %esp                         /* seven local variables */      ; \
49									   ; \
50   pushl %edi                                                              ; \
51   pushl %esi                                                              ; \
52   pushl %ebx                                                              ; \
53   pushw %es                                                               ; \
54									   ; \
55   movl S_BMP, %edx                       /* edx = bitmap pointer */       ; \
56   movl S_SPRITE, %esi                    /* esi = sprite pointer */       ; \
57									   ; \
58   movw BMP_SEG(%edx), %es                /* segment selector */           ; \
59									   ; \
60   cmpl $0, BMP_CLIP(%edx)                /* test bmp->clip */             ; \
61   jz name##_no_clip                                                       ; \
62									   ; \
63   movl BMP_CT(%edx), %eax                /* bmp->ct */                    ; \
64   subl S_Y, %eax                         /* eax -= y */                   ; \
65   jge name##_tgap_ok                                                      ; \
66   xorl %eax, %eax                                                         ; \
67name##_tgap_ok:                                                            ; \
68   movl %eax, S_TGAP                      /* set tgap */                   ; \
69									   ; \
70   movl BMP_H(%esi), %ebx                 /* sprite->h */                  ; \
71   movl BMP_CB(%edx), %ecx                /* bmp->cb */                    ; \
72   subl S_Y, %ecx                         /* ecx -= y */                   ; \
73   cmpl %ebx, %ecx                        /* check bottom clipping */      ; \
74   jg name##_height_ok                                                     ; \
75   movl %ecx, %ebx                                                         ; \
76name##_height_ok:                                                          ; \
77   subl %eax, %ebx                        /* height -= tgap */             ; \
78   jle name##_done                                                         ; \
79   movl %ebx, S_H                         /* set h */                      ; \
80									   ; \
81   movl BMP_CL(%edx), %eax                /* bmp->cl */                    ; \
82   subl S_X, %eax                         /* eax -= x */                   ; \
83   jge name##_lgap_ok                                                      ; \
84   xorl %eax, %eax                                                         ; \
85name##_lgap_ok:                                                            ; \
86   movl %eax, S_LGAP                      /* set lgap */                   ; \
87									   ; \
88   movl BMP_W(%esi), %ebx                 /* sprite->w */                  ; \
89   movl BMP_CR(%edx), %ecx                /* bmp->cr */                    ; \
90   subl S_X, %ecx                         /* ecx -= x */                   ; \
91   cmpl %ebx, %ecx                        /* check left clipping */        ; \
92   jg name##_width_ok                                                      ; \
93   movl %ecx, %ebx                                                         ; \
94name##_width_ok:                                                           ; \
95   subl %eax, %ebx                        /* width -= lgap */              ; \
96   jle name##_done                                                         ; \
97   movl %ebx, S_W                         /* set w */                      ; \
98									   ; \
99   jmp name##_clip_done                                                    ; \
100									   ; \
101   _align_                                                                 ; \
102name##_no_clip:                                                            ; \
103   movl $0, S_TGAP                                                         ; \
104   movl $0, S_LGAP                                                         ; \
105   movl BMP_W(%esi), %eax                                                  ; \
106   movl %eax, S_W                         /* w = sprite->w */              ; \
107   movl BMP_H(%esi), %eax                                                  ; \
108   movl %eax, S_H                         /* h = sprite->h */              ; \
109									   ; \
110   _align_                                                                 ; \
111name##_clip_done:
112
113
114
115/* cleans up the stack after a sprite draw operation */
116#define END_SPRITE_DRAW()                                                    \
117   popw %es                                                                ; \
118									   ; \
119   movl S_BMP, %edx                                                        ; \
120   UNWRITE_BANK()                                                          ; \
121									   ; \
122   popl %ebx                                                               ; \
123   popl %esi                                                               ; \
124   popl %edi                                                               ; \
125   movl %ebp, %esp                                                         ; \
126   popl %ebp
127
128
129
130/* sets up the inner sprite drawing loop, loads registers, etc */
131#define SPRITE_LOOP(name)                                                    \
132sprite_y_loop_##name:                                                      ; \
133   movl S_Y, %eax                         /* load line */                  ; \
134   WRITE_BANK()                           /* select bank */                ; \
135   addl S_X, %eax                         /* add x offset */               ; \
136   movl S_W, %ecx                         /* x loop counter */             ; \
137									   ; \
138   _align_                                                                 ; \
139sprite_x_loop_##name:
140
141
142
143/* ends the inner (x) part of a sprite drawing loop */
144#define SPRITE_END_X(name)                                                   \
145   decl %ecx                                                               ; \
146   jg sprite_x_loop_##name
147
148
149
150/* ends the outer (y) part of a sprite drawing loop */
151#define SPRITE_END_Y(name)                                                   \
152   addl S_SGAP, %esi                      /* skip sprite bytes */          ; \
153   incl S_Y                               /* next line */                  ; \
154   decl S_H                               /* loop counter */               ; \
155   jg sprite_y_loop_##name
156
157
158
159/* sets up the inner translucent sprite drawing loop, loads registers, etc */
160#define T_SPRITE_LOOP(name)                                                  \
161sprite_y_loop_##name:                                                      ; \
162   movl S_BMP, %edx                       /* load bitmap pointer */        ; \
163   movl S_Y, %eax                         /* load line */                  ; \
164   READ_BANK()                            /* select read bank */           ; \
165   movl %eax, %ecx                        /* read address in ecx */        ; \
166   movl S_Y, %eax                         /* reload line */                ; \
167   WRITE_BANK()                           /* select write bank */          ; \
168   subl %eax, %ecx                        /* convert ecx to offset */      ; \
169   addl S_X, %eax                         /* add x offset */               ; \
170   movl S_W, %edx                         /* x loop counter */             ; \
171   movl %edx, S_C                         /* store */                      ; \
172									   ; \
173   _align_                                                                 ; \
174sprite_x_loop_##name:
175
176
177
178/* sets up the inner truecolor translucent sprite drawing loop */
179#define TT_SPRITE_LOOP(name, readreg)                                        \
180sprite_y_loop_##name:                                                      ; \
181   movl S_BMP, %edx                       /* load bitmap pointer */        ; \
182   movl S_Y, %eax                         /* load line */                  ; \
183   READ_BANK()                            /* select read bank */           ; \
184   movl %eax, readreg                     /* read address in readreg */    ; \
185   movl S_Y, %eax                         /* reload line */                ; \
186   WRITE_BANK()                           /* select write bank */          ; \
187   subl %eax, readreg                     /* convert readreg to offset */  ; \
188   movl S_W, %edx                         /* x loop counter */             ; \
189   addl S_X, %eax                         /* add x offset */               ; \
190   movl %edx, S_C                         /* store */                      ; \
191   movl %eax, %ebx                        /* move dest address */          ; \
192									   ; \
193   _align_                                                                 ; \
194sprite_x_loop_##name:
195
196
197
198/* sets up the inner truecolor lit sprite drawing loop */
199#define LT_SPRITE_LOOP(name)                                                 \
200sprite_y_loop_##name:                                                      ; \
201   movl S_BMP, %edx                       /* load bitmap pointer */        ; \
202   movl S_Y, %eax                         /* load line */                  ; \
203   WRITE_BANK()                           /* select write bank */          ; \
204   movl S_W, %edx                         /* x loop counter */             ; \
205   addl S_X, %eax                         /* add x offset */               ; \
206   movl %edx, S_C                         /* store */                      ; \
207   movl %eax, %ebx                        /* move dest address */          ; \
208									   ; \
209   _align_                                                                 ; \
210sprite_x_loop_##name:
211
212
213
214/* ends the inner (x) part of a translucent sprite drawing loop */
215#define T_SPRITE_END_X(name)                                                 \
216   decl S_C                                                                ; \
217   jg sprite_x_loop_##name
218
219
220
221
222/* generic framework for constructing RLE sprite drawing routines, shared
223 * between the 8, 16, 24, and 32 bit versions of the code...
224 */
225
226
227#define R_BMP           ARG1
228#define R_SPRITE        ARG2
229#define R_X             ARG3
230#define R_Y             ARG4
231#define R_COLOR         ARG5
232
233#define R_LGAP          -4(%ebp)
234#define R_W             -8(%ebp)
235#define R_H             -12(%ebp)
236#define R_TMP           -16(%ebp)
237#define R_TMP2          -20(%ebp)
238
239
240
241/* helper macro for drawing RLE sprites */
242#define DO_RLE(name, bpp, suf, areg, eolmarker)                              \
243   pushl %ebp                                                              ; \
244   movl %esp, %ebp                                                         ; \
245   subl $20, %esp                                                          ; \
246									   ; \
247   pushl %ebx                                                              ; \
248   pushl %esi                                                              ; \
249   pushl %edi                                                              ; \
250   pushw %es                                                               ; \
251									   ; \
252   movl $0, R_LGAP               /* normally zero gap on left */           ; \
253   movl R_SPRITE, %esi           /* esi = sprite pointer */                ; \
254   movl RLE_W(%esi), %eax        /* read sprite width */                   ; \
255   movl %eax, R_W                                                          ; \
256   movl RLE_H(%esi), %eax        /* read sprite height */                  ; \
257   movl %eax, R_H                                                          ; \
258   addl $RLE_DAT, %esi           /* points to start of RLE data */         ; \
259									   ; \
260   movl R_BMP, %edx              /* edx = bitmap pointer */                ; \
261   movw BMP_SEG(%edx), %es       /* select segment */                      ; \
262   cld                                                                     ; \
263									   ; \
264   cmpl $0, BMP_CLIP(%edx)       /* test clip flag */                      ; \
265   je name##_noclip                                                        ; \
266									   ; \
267   movl R_Y, %ecx                /* ecx = Y */                             ; \
268									   ; \
269name##_clip_top:                                                           ; \
270   cmpl %ecx, BMP_CT(%edx)       /* test top clipping */                   ; \
271   jle name##_top_ok                                                       ; \
272									   ; \
273   incl %ecx                     /* increment Y */                         ; \
274   decl R_H                      /* decrement height */                    ; \
275   jle name##_done                                                         ; \
276									   ; \
277   _align_                                                                 ; \
278name##_clip_top_loop:                                                      ; \
279   lods##suf                     /* find zero EOL marker in RLE data */    ; \
280   cmp##suf eolmarker, areg                                                ; \
281   jne name##_clip_top_loop                                                ; \
282									   ; \
283   jmp name##_clip_top                                                     ; \
284									   ; \
285   _align_                                                                 ; \
286name##_top_ok:                                                             ; \
287   movl %ecx, R_Y                /* store clipped Y */                     ; \
288									   ; \
289   addl R_H, %ecx                /* ecx = Y + height */                    ; \
290   subl BMP_CB(%edx), %ecx       /* test bottom clipping */                ; \
291   jl name##_bottom_ok                                                     ; \
292									   ; \
293   subl %ecx, R_H                /* clip on the bottom */                  ; \
294   jle name##_done                                                         ; \
295									   ; \
296   _align_                                                                 ; \
297name##_bottom_ok:                                                          ; \
298   movl BMP_CL(%edx), %eax       /* check left clipping */                 ; \
299   subl R_X, %eax                                                          ; \
300   jle name##_left_ok                                                      ; \
301									   ; \
302   movl %eax, R_LGAP             /* clip on the left */                    ; \
303   addl %eax, R_X                                                          ; \
304   subl %eax, R_W                                                          ; \
305   jle name##_done                                                         ; \
306									   ; \
307   _align_                                                                 ; \
308name##_left_ok:                                                            ; \
309   movl R_X, %eax                /* check right clipping */                ; \
310   addl R_W, %eax                                                          ; \
311   subl BMP_CR(%edx), %eax                                                 ; \
312   jle name##_no_right_clip                                                ; \
313									   ; \
314   subl %eax, R_W                                                          ; \
315   jl name##_done                                                          ; \
316   jmp name##_clip_y_loop                                                  ; \
317									   ; \
318   _align_                                                                 ; \
319name##_no_right_clip:                                                      ; \
320   cmpl $0, R_LGAP               /* can we use the fast noclip drawer? */  ; \
321   je name##_noclip                                                        ; \
322									   ; \
323									   ; \
324   /* slower version of the drawer for sprites that need clipping */       ; \
325   _align_                                                                 ; \
326name##_clip_y_loop:                                                        ; \
327   INIT_RLE_LINE()                                                         ; \
328									   ; \
329   movl R_W, %ebx                                                          ; \
330   movl R_LGAP, %ecx                                                       ; \
331									   ; \
332name##_clip_lgap_loop:                                                     ; \
333   lods##suf                     /* read a command byte */                 ; \
334   test##suf areg, areg          /* and test it */                         ; \
335   js name##_clip_lgap_zeros                                               ; \
336									   ; \
337   RLE_ZEX_EAX()                 /* skip a solid run */                    ; \
338   leal (%esi, %eax, bpp), %esi                                            ; \
339   subl %eax, %ecx                                                         ; \
340   jge name##_clip_lgap_loop                                               ; \
341									   ; \
342   leal (%esi, %ecx, bpp), %esi  /* oops, we overshot */                   ; \
343   negl %ecx                                                               ; \
344   movl %ecx, %eax                                                         ; \
345   jmp name##_clip_x_loop                                                  ; \
346									   ; \
347   _align_                                                                 ; \
348name##_clip_lgap_zeros:                                                    ; \
349   RLE_SEX_EAX()                 /* skip a run of zeros */                 ; \
350   addl %eax, %ecx                                                         ; \
351   jge name##_clip_lgap_loop                                               ; \
352									   ; \
353   movl %ecx, %eax               /* oops, we overshot */                   ; \
354									   ; \
355   _align_                                                                 ; \
356name##_clip_x_loop:                                                        ; \
357   TEST_RLE_COMMAND(name##_clip_x_done, name##_clip_skip_zeros)            ; \
358									   ; \
359   RLE_ZEX_ECX()                 /* write a string of pixels */            ; \
360   subl %ecx, %ebx                                                         ; \
361   jle name##_clip_string                                                  ; \
362									   ; \
363   SLOW_RLE_RUN(0)                                                         ; \
364   lods##suf                     /* read next command byte */              ; \
365   jmp name##_clip_x_loop                                                  ; \
366									   ; \
367   _align_                                                                 ; \
368name##_clip_string:                                                        ; \
369   addl %ebx, %ecx               /* only write part of the string */       ; \
370   jle name##_clip_altogether                                              ; \
371   SLOW_RLE_RUN(1)                                                         ; \
372name##_clip_altogether:                                                    ; \
373   negl %ebx                                                               ; \
374   leal (%esi, %ebx, bpp), %esi                                            ; \
375   jmp name##_clip_skip_rgap                                               ; \
376									   ; \
377   _align_                                                                 ; \
378name##_clip_skip_zeros:                                                    ; \
379   RLE_SEX_EAX()                 /* skip over a string of zeros */         ; \
380   negl %eax                                                               ; \
381   ADD_EAX_EDI()                                                           ; \
382   subl %eax, %ebx                                                         ; \
383   jle name##_clip_skip_rgap                                               ; \
384									   ; \
385   lods##suf                     /* read next command byte */              ; \
386   jmp name##_clip_x_loop                                                  ; \
387									   ; \
388   _align_                                                                 ; \
389name##_clip_skip_rgap:                                                     ; \
390   lods##suf                     /* skip forward to zero EOL marker */     ; \
391   cmp##suf eolmarker, areg                                                ; \
392   jne name##_clip_skip_rgap                                               ; \
393									   ; \
394name##_clip_x_done:                                                        ; \
395   incl R_Y                                                                ; \
396   decl R_H                                                                ; \
397   jg name##_clip_y_loop                                                   ; \
398   jmp name##_done                                                         ; \
399									   ; \
400									   ; \
401   /* fast drawer for sprites that don't need clipping */                  ; \
402   _align_                                                                 ; \
403name##_noclip:                                                             ; \
404   INIT_FAST_RLE_LOOP()                                                    ; \
405									   ; \
406   _align_                                                                 ; \
407name##_noclip_y_loop:                                                      ; \
408   INIT_RLE_LINE()                                                         ; \
409									   ; \
410   _align_                                                                 ; \
411name##_noclip_x_loop:                                                      ; \
412   lods##suf                     /* read a command byte */                 ; \
413   TEST_RLE_COMMAND(name##_noclip_x_done, name##_noclip_skip_zeros)        ; \
414									   ; \
415   RLE_ZEX_ECX()                 /* write a string of pixels */            ; \
416   FAST_RLE_RUN()                                                          ; \
417   jmp name##_noclip_x_loop                                                ; \
418									   ; \
419   _align_                                                                 ; \
420name##_noclip_skip_zeros:                                                  ; \
421   neg##suf areg                 /* skip over a string of zeros */         ; \
422   RLE_ZEX_EAX()                                                           ; \
423   ADD_EAX_EDI()                                                           ; \
424   jmp name##_noclip_x_loop                                                ; \
425									   ; \
426   _align_                                                                 ; \
427name##_noclip_x_done:                                                      ; \
428   incl R_Y                                                                ; \
429   decl R_H                                                                ; \
430   jg name##_noclip_y_loop                                                 ; \
431									   ; \
432									   ; \
433name##_done:                                                               ; \
434   popw %es                                                                ; \
435									   ; \
436   movl R_BMP, %edx                                                        ; \
437   UNWRITE_BANK()                                                          ; \
438									   ; \
439   popl %edi                                                               ; \
440   popl %esi                                                               ; \
441   popl %ebx                                                               ; \
442   movl %ebp, %esp                                                         ; \
443   popl %ebp                     /* finished drawing an RLE sprite */
444
445
446
447
448#endif          /* ifndef ALLEGRO_I386_SPRITE_INC */
449
450