/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Compiled sprite routines for the i386. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include #include "allegro.h" #include "allegro/internal/aintern.h" #include "opcodes.h" /* compile_sprite: * Helper function for making compiled sprites. */ static void *compile_sprite(BITMAP *b, int l, int planar, int *len) { int x, y; int offset; int run; int run_pos; int compiler_pos = 0; int xc = planar ? 4 : 1; unsigned long *addr; void *p; #ifdef ALLEGRO_COLOR16 unsigned short *p16; #endif #if defined ALLEGRO_COLOR24 || defined ALLEGRO_COLOR32 unsigned long *p32; #endif for (y=0; yh; y++) { /* for linear bitmaps, time for some bank switching... */ if (!planar) { COMPILER_MOV_EDI_EAX(); COMPILER_CALL_ESI(); COMPILER_ADD_ECX_EAX(); } offset = 0; x = l; /* compile a line of the sprite */ while (x < b->w) { switch (bitmap_color_depth(b)) { #ifdef ALLEGRO_COLOR8 case 8: /* 8 bit version */ if (b->line[y][x]) { run = 0; run_pos = x; while ((run_posw) && (b->line[y][run_pos])) { run++; run_pos += xc; } while (run >= 4) { COMPILER_MOVL_IMMED(offset, ((int)b->line[y][x]) | ((int)b->line[y][x+xc] << 8) | ((int)b->line[y][x+xc*2] << 16) | ((int)b->line[y][x+xc*3] << 24)); x += xc*4; offset += 4; run -= 4; } if (run >= 2) { COMPILER_MOVW_IMMED(offset, ((int)b->line[y][x]) | ((int)b->line[y][x+xc] << 8)); x += xc*2; offset += 2; run -= 2; } if (run > 0) { COMPILER_MOVB_IMMED(offset, b->line[y][x]); x += xc; offset++; } } else { x += xc; offset++; } break; #endif #ifdef ALLEGRO_COLOR16 case 15: case 16: /* 16 bit version */ p16 = (unsigned short *)b->line[y]; if (p16[x] != b->vtable->mask_color) { run = 0; run_pos = x; while ((run_posw) && (p16[run_pos] != b->vtable->mask_color)) { run++; run_pos++; } while (run >= 2) { COMPILER_MOVL_IMMED(offset, ((int)p16[x]) | ((int)p16[x+1] << 16)); x += 2; offset += 4; run -= 2; } if (run > 0) { COMPILER_MOVW_IMMED(offset, p16[x]); x++; offset += 2; run--; } } else { x++; offset += 2; } break; #endif #ifdef ALLEGRO_COLOR24 case 24: /* 24 bit version */ p32 = (unsigned long *)b->line[y]; if (((*((unsigned long *)(((unsigned char *)p32)+x*3)))&0xFFFFFF) != (unsigned)b->vtable->mask_color) { run = 0; run_pos = x; while ((run_posw) && (((*((unsigned long *)(((unsigned char *)p32)+run_pos*3)))&0xFFFFFF) != (unsigned)b->vtable->mask_color)) { run++; run_pos++; } while (run >= 4) { addr = ((unsigned long *)(((unsigned char *)p32)+x*3)); COMPILER_MOVL_IMMED(offset, addr[0]); offset += 4; COMPILER_MOVL_IMMED(offset, addr[1]); offset += 4; COMPILER_MOVL_IMMED(offset, addr[2]); offset += 4; x += 4; run -= 4; } switch (run) { case 3: addr = ((unsigned long *)(((unsigned char *)p32)+x*3)); COMPILER_MOVL_IMMED(offset, addr[0]); offset += 4; COMPILER_MOVL_IMMED(offset, addr[1]); offset += 4; COMPILER_MOVB_IMMED(offset, *(((unsigned short *)addr)+4)); offset++; x += 3; run -= 3; break; case 2: addr = ((unsigned long *)(((unsigned char *)p32)+x*3)); COMPILER_MOVL_IMMED(offset, addr[0]); offset += 4; COMPILER_MOVW_IMMED(offset, *(((unsigned short *)addr)+2)); offset += 2; x += 2; run -= 2; break; case 1: addr = ((unsigned long *)((unsigned char *)p32+x*3)); COMPILER_MOVW_IMMED(offset, (unsigned short )addr[0]); offset += 2; COMPILER_MOVB_IMMED(offset, *((unsigned char *)(((unsigned short *)addr)+1))); offset++; x++; run--; break; default: break; } } else { x++; offset += 3; } break; #endif #ifdef ALLEGRO_COLOR32 case 32: /* 32 bit version */ p32 = (unsigned long *)b->line[y]; if (p32[x] != (unsigned)b->vtable->mask_color) { run = 0; run_pos = x; while ((run_posw) && (p32[run_pos] != (unsigned)b->vtable->mask_color)) { run++; run_pos++; } while (run > 0) { COMPILER_MOVL_IMMED(offset, p32[x]); x++; offset += 4; run--; } } else { x++; offset += 4; } break; #endif } } /* move on to the next line */ if (y+1 < b->h) { if (planar) { COMPILER_ADD_ECX_EAX(); } else { COMPILER_INC_EDI(); } } } COMPILER_RET(); p = malloc(compiler_pos); if (p) { memcpy(p, _scratch_mem, compiler_pos); *len = compiler_pos; } return p; } /* get_compiled_sprite: * Creates a compiled sprite based on the specified bitmap. */ COMPILED_SPRITE *get_compiled_sprite(BITMAP *bitmap, int planar) { COMPILED_SPRITE *s; int plane; s = malloc(sizeof(COMPILED_SPRITE)); if (!s) return NULL; s->planar = planar; s->color_depth = bitmap_color_depth(bitmap); s->w = bitmap->w; s->h = bitmap->h; for (plane=0; plane<4; plane++) { s->proc[plane].draw = NULL; s->proc[plane].len = 0; } for (plane=0; plane < (planar ? 4 : 1); plane++) { s->proc[plane].draw = compile_sprite(bitmap, plane, planar, &s->proc[plane].len); if (!s->proc[plane].draw) { destroy_compiled_sprite(s); return NULL; } } return s; } /* destroy_compiled_sprite: * Destroys a compiled sprite structure returned by get_compiled_sprite(). */ void destroy_compiled_sprite(COMPILED_SPRITE *sprite) { int plane; if (sprite) { for (plane=0; plane<4; plane++) if (sprite->proc[plane].draw) free(sprite->proc[plane].draw); free(sprite); } }