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