OSDN Git Service

[VM][FMTOWNS][WIP] Implementing.Still WIP.
authorK.Ohta <whatisthis.sowhat@gmail.com>
Sun, 23 Sep 2018 20:02:54 +0000 (05:02 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Sun, 23 Sep 2018 20:02:54 +0000 (05:02 +0900)
source/src/vm/fmtowns/towns_sprite.cpp
source/src/vm/fmtowns/towns_sprite.h

index b27495e..e3b0a91 100644 (file)
@@ -35,6 +35,7 @@ void TOWNS_SPRITE::initialize(void)
        for(int i = 0; i < 256; i++) {
                color_cached[i] = false;
        }
+       use_cache = false; // ToDo: Enable cache.
 }
 
 void TOWNS_SPRITE::reset()
@@ -66,6 +67,7 @@ void TOWNS_SPRITE::set_sprite_attribute(int table_num, uint16_t num_attr)
        bool halfx = ((num_attr &  0x0400) != 0);
        bool halfy = ((num_attr &  0x0800) != 0);
        bool enable_offset = ((num_attr & 0x8000) != 0);
+       
        sprite_table[table_num].num = num;
        sprite_table[table_num].rotate_type = rotate_type;
        sprite_table[table_num].is_halfx = halfx;
@@ -83,124 +85,26 @@ void TOWNS_SPRITE::set_sprite_color(int table_num, uint16_t color_table_num)
        sprite_table[table_num].is_disp   = ((color_table_num & 0x2000) != 0);
 }
 
-void TOWNS_SPRITE::render_not_rotate(int num, uint16* dst_pixel, int width, int height, int stride)
-{
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint8_t* addr;
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       if(sprite_table[num].is_32768) {
-       } else {
-               addr = &(pattern_ram[(sprite_table[num].num - 128) << 3]);
-               int ystep = (cache_index[num].is_halfy) ? 2 : 1;
-               int xstep = (cache_index[num].is_halfx) ? 2 : 1;
-               int w = (cache_index[num].is_halfy) ? 8 : 16;
-               int h = (cache_index[num].is_halfx) ? 8 : 16;
-               int color = sprite_table[num].color;
-               if(color < 256) return;
-               if(color > 511) return;
-               color = color - 256;
-               uint16_t* p;
-               uint16_t* m;
-               uint16_t* q;
-               uint16_t* dp;
-               int yy = 0;
-               uint8_t pixels[16];
-               uint8_t pixels_lo[16];
-               uint8_t pixels_hi[16];
-               uint16_t masks[16];
-               uint16_t tpixels[16];
-               uint16_t t2pixels[16];
-               uint16_t* color_index = (uint16_t*)(&color_index_ram[color << 5]);
-               for(int y = 0; y < 16; y += ystep) {
-                       p = &(cache_pixel[yy << 4]);
-                       m = &(cache_mask[yy << 4]);
-                       q = (uint8_t*)qp;
-                       q = &q[y << 3];
-                       dp = &(dst_pixel[yy * stride]);
-                       if(cache_index[num].is_halfx) {
-                               for(int x = 0; x < 8; x++) {
-                                       pixels[x] = q[x];
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       pixels[x] = pixels[x] & 0xf0;
-                               }
-                               
-                               for(int x = 0; x < 8; x++) {
-                                       masks[x] = (pixels[x] == 0) ? 0xffff : 0x0000;
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       p[x] = color_index[pixels[x]];
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       m[x] = masks[x];
-                               }
-                               // Draw to buffer
-                               for(int x = 0; x < 8; x++) {
-                                       tpixels[x] = dp[x] & masks[x];
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       pixels[x] = p[x] & ~masks[x];
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       dp[x] = pixels[x] | tpixels[x];
-                               }
-                       } else {
-                               for(int x = 0; x < 8; x++) {
-                                       pixels[x] = q[x];
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       pixels_hi[x] = pixels[x] & 0xf0;
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       pixels_lo[x] = pixels[x] & 0x0f;
-                               }
-                               
-                               for(int x = 0; x < 8; x++) {
-                                       masks[x << 1] = (pixels_hi[x] == 0) ? 0xffff : 0x0000;
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       masks[(x << 1) + 1] = (pixels_lo[x] == 0) ? 0xffff : 0x0000;
-                               }
-                               for(int x = 0; x < 8; x++) {
-                                       p[x << 1] = color_index[pixels_hi[x]];
-                                       p[(x << 1) + 1] = color_index[pixels_lo[x]];
-                               }
-                               for(int x = 0; x < 16; x++) {
-                                       m[x] = masks[x];
-                               }
-                               // Draw to buffer
-                               for(int x = 0; x < 16; x++) {
-                                       tpixels[x] = dp[x] & masks[x];
-                               }
-                               for(int x = 0; x < 16; x++) {
-                                       t2pixels[x] = p[x] & ~masks[x];
-                               }
-                               for(int x = 0; x < 16; x++) {
-                                       dp[x] = t2pixels[x] | tpixels[x];
-                               }
-                       }
-                       yy++;
-               }
-       }
-}
-
 
 void TOWNS_SPRITE::render_sprite(int num, uint16* dst_pixel, int width, int height, int stride)
 {
+       uint16_t sprite_limit = reg_index & 0x3ff;
+       if(sprite_limit == 0) sprite_limit = 1024;
        if(num < 0) return;
        if(num >= sprite_limit) return;
        if(num >= 1024) return;
        if(stride <= 0) return;
        if(stride > 512) return;
        if(!(sprite_table[num].is_disp)) return;
-       
+
+       if(use_cache) {
        for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
                if(!(cache_index[i].is_use)) continue;
                if(cache_index[i].attribute == sprite_table[num].attribute) {
                        if(cache_index[i].is_32768 == sprite_table[num].is_32768) {
                                if(cache_index[i].is_32768) {
                                        //
+                                       // ToDo: Integrate to not hitting cache.
                                        int h = (cache_index[i].is_halfy) ? 8 : 16;
                                        int w = (cache_index[i].is_halfx) ? 8 : 16;
                                        if(height < h) h = height;
@@ -246,6 +150,7 @@ void TOWNS_SPRITE::render_sprite(int num, uint16* dst_pixel, int width, int heig
                                                uint16_t* rp = &qp[y << 4];
                                                uint16_t* rm = &qm[y << 4];
                                                ppp = pp;
+__DECL_VECTORIZED_LOOP                         
                                                for(x = 0; x < w; x++) {
                                                        uint16_t pixel = *rp;
                                                        uint16_t dpixel = *ppp;
@@ -262,6 +167,7 @@ void TOWNS_SPRITE::render_sprite(int num, uint16* dst_pixel, int width, int heig
                        }
                }
        }
+       }
        // Cache Not hit
        int target_num = -1;
        for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
@@ -284,12 +190,158 @@ void TOWNS_SPRITE::render_sprite(int num, uint16* dst_pixel, int width, int heig
        cache_index[target_num].masks = (uint16_t*)(&(cache_masks[target_num][0]));
        cache_index[target_num].color = sprite_table[num].color;
        cache_index[target_num].num = sprite_table[num].num;
-       color_cached[(cache_index[target_num].color) & 0xff] = true;
+       if(!(cache_index[target_num].is_32768)) {
+               color_cached[(cache_index[target_num].color) & 0xff] = true;
+       }
        pattern_cached[sprite_table[num].num] = true; // OK?
 
-       render_base(num, dst_pixel, width, height, stride);
+       switch((sprite_table[num].rotate) & 7) {
+       case 0:
+               rot_type = ROT_FMTOWNS_SPRITE_0;
+               is_mirror = false;
+               break;
+       case 1:
+               rot_type = ROT_FMTOWNS_SPRITE_180;
+               is_mirror = true;
+               break;
+       case 2:
+               rot_type = ROT_FMTOWNS_SPRITE_180;
+               is_mirror = false;
+               break;
+       case 3:
+               rot_type = ROT_FMTOWNS_SPRITE_0;
+               is_mirror = true;
+               break;
+       case 4:
+               rot_type = ROT_FMTOWNS_SPRITE_270;
+               is_mirror = true;
+               break;
+       case 5:
+               rot_type = ROT_FMTOWNS_SPRITE_90;
+               is_mirror = false;
+               break;
+       case 6:
+               rotate = false;
+               rot_type = ROT_FMTOWNS_SPRITE_270;
+               is_mirror = false;
+               break;
+       case 7:
+               rot_type = ROT_FMTOWNS_SPRITE_90;
+               is_mirror = true;
+               break;
+       }
+       uint32_t index_num = cache_index[target_num].attribute & 0x3ff;
+       if(index_num < 128) return;
+       
+       uint8_t* src = &(pattern_ram[index_num << 7]);
+       bool is_32768 = cache_index[target_num].is_32768;
+       bool is_halfx = cache_index[target_num].is_halfx;
+       bool is_halfy = cache_index[target_num].is_halfy;
+
+       switch(rot_type) {
+       case ROT_FMTOWNS_SPRITE_00:
+               rot_data_0(src, is_mirror, cache_index[target_num].pixels, cache_index[target_num].masks, is_32768, is_halfx, is_halfy);
+               break;
+       case ROT_FMTOWNS_SPRITE_90:
+               rot_data_0(src, is_mirror, cache_index[target_num].pixels, cache_index[target_num].masks, is_32768, is_halfx, is_halfy);
+               break;
+       case ROT_FMTOWNS_SPRITE_180:
+               rot_data_0(src, is_mirror, cache_index[target_num].pixels, cache_index[target_num].masks, is_32768, is_halfx, is_halfy);
+               break;
+       case ROT_FMTOWNS_SPRITE_270:
+               rot_data_0(src, is_mirror, cache_index[target_num].pixels, cache_index[target_num].masks, is_32768, is_halfx, is_halfy);
+               break;
+       }
+       // ToDo: wrap round.This is still bogus implement.
+       // ToDo: Separate writing buffer and integrate cache.
+       // copy cache to buffer
+       uint16_t* pp = cache_index[target_num].pixels;
+       uint16_t* pq = cache_index[target_num].masks;
+       uint16_t* pd = dst_pixel;
+       if(is_halfx) {
+               uint16_t cacheline[8];
+               uint16_t mcacheline[8];
+               uint16_t pcacheline[8];
+               int ysize = 16;
+               if(is_halfy) {
+                       ysize = 8;
+               }
+               for(int y = 0; y < ysize; y++) {
+__DECL_VECTORIZED_LOOP                         
+                       for(int x = 0; x < 8; x++) {
+                               cacheline[x] = pp[x];
+                               mcacheline[x] = pq[x];
+                       }
+__DECL_VECTORIZED_LOOP                         
+                       for(int x = 0; x < 8; x++) {
+                               pcacheline[x] = pd[x] & mcacheline[x];
+                               mcacheline[x] = ~mcacheline[x];
+                               cacheline[x] = cacheline[x] & mcacheline[x];
+                       }
+__DECL_VECTORIZED_LOOP                         
+                       for(int x = 0; x < 8; x++) {
+                               pd[x] = pcacheline[x] | mcacheline[x];
+                       }
+                       pd = pd + stride;
+                       pp += 8;
+                       pq += 8;
+               }
+       } else { // Not halfx
+               uint16_t cacheline[16];
+               uint16_t mcacheline[16];
+               uint16_t pcacheline[16];
+               int ysize = 16;
+               if(is_halfy) {
+                       ysize = 8;
+               }
+               for(int y = 0; y < ysize; y++) {
+__DECL_VECTORIZED_LOOP                         
+                       for(int x = 0; x < 16; x++) {
+                               cacheline[x] = pp[x];
+                               mcacheline[x] = pq[x];
+                       }
+__DECL_VECTORIZED_LOOP                         
+                       for(int x = 0; x < 16; x++) {
+                               pcacheline[x] = pd[x] & mcacheline[x];
+                               mcacheline[x] = ~mcacheline[x];
+                               cacheline[x] = cacheline[x] & mcacheline[x];
+                       }
+__DECL_VECTORIZED_LOOP                         
+                       for(int x = 0; x < 16; x++) {
+                               pd[x] = pcacheline[x] | mcacheline[x];
+                       }
+                       pd = pd + stride;
+                       pp += 8;
+                       pq += 8;
+               }
+       }
 }
 
+void TOWNS_SPRITE::render(uint16_t *buffer, int w, int h, int stride)
+{
+       // ToDo: Implement Register #2-5
+       uint16_t lot = reg_index & 0x3ff;
+       if(lot == 0) lot = 1024;
+       if((w <= 0) || (h <= 0)) return;
+       if(stride <= 0) return;
+       // Clear buffer?
+       memset(buffer, 0x00, w * h * sizeof(uint16_t));
+       
+       if(reg_spen) {
+               for(int i = 0; i < (int)lot; i++) {
+                       uint16_t* index_base = &(index_ram[i << 2]);
+                       uint16_t xaddr = index_base[0] & 0x1ff;
+                       uint16_t yaddr = index_base[1] & 0x1ff;
+                       if((xaddr < (uint16_t)w) && (yaddr < (uint16_t)h)) {
+                               // ToDo: wrap round.This is still bogus implement.
+                               uint16_t* addr = &(buffer[yaddr * w + xaddr]);
+                               render_sprite(i, addr, width, height, stride);
+                       }
+               }
+       }
+}
+// ToDo: Discard cache(s) if dirty color index and if used this cache at 16 colors.
+// ToDo: Discard cache(s) if dirty 
 void TOWNS_SPRITE::write_io8(uint32_t addr, uint32_t data)
 {
        reg_addr = addr & 7;
@@ -440,6 +492,9 @@ uint32_t TOWNS_SPRITE::read_data32(uint32_t addr)
 void TOWNS_SPRITE::write_data8(uint32_t addr, uint32_t data)
 {
        uint32_t nbank;
+       uint32_t uaddr;
+       uint16_t tmp16;
+       uint8_t tmp8;
        uint8_t* p8;
        pair_t tval;
        if((addr >= 0x81000000) && (addr < 0x81020000)) {
@@ -447,54 +502,107 @@ void TOWNS_SPRITE::write_data8(uint32_t addr, uint32_t data)
        } else {
                nbank = 0; // OK?
        }
+       
        switch(nbank) {
        case 0:
        case 1:
-               tval.w.l = index_ram[(addr & 0x1ffe) >> 1];
+               uaddr = (addr & 0x1ffe) >> 1;
+               tval.w.l = index_ram[uaddr];
+               tmp16 = tval.w.l;
                if((addr & 1) == 0) { // Lo
                        tval.b.l = (uint8_t)(data & 0xff);
                } else {
                        tval.b.h = (uint8_t)(data & 0xff);
                }
-               index_ram[(addr & 0x1ffe) >> 1] = tval.w.l;
+               if(use_cache) {
+               if(uaddr == 2) { // ATTR 
+                       if((tmp16 & 0x7c00) != (tval.w.l & 0x7c00)) {
+                               // Search cache and Discard cache
+                       }
+               } else if(uaddr == 3) {
+                       if((tmp16 & 0x8fff) != (tval.w.l & 0x8fff)) {
+                               // Search cache and Discard cache
+                       }
+               }
+               }
+               index_ram[uaddr] = tval.w.l;
                break;
        case 2:
        case 3:
                // ToDO: Discard cache
-               tval.w.l = color_ram[(addr & 0x1ffe) >> 1];
+               uaddr = (addr & 0x1ffe) >> 1;
+               tval.w.l = color_ram[uaddr];
+               tmp16 = tval.w.l;
                if((addr & 1) == 0) { // Lo
                        tval.b.l = (uint8_t)(data & 0xff);
                } else {
                        tval.b.h = (uint8_t)(data & 0xff);
                }
-               color_ram[(addr & 0x1ffe) >> 1] = tval.w.l;
-               if(color_cached[(addr & 0x1ffe) >> 5]) {
-                       uint32_t nnum = (addr & 0x1ffe) >> 5;
-                       for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
-                               if(cache_index[i].color == (uint16_t)(nnum + 256)) {
-                                       if(cache_index[i].is_use) {
-                                               clear_cache(i);
+               if(use_cache) {
+               if(tmp16 != tval.w.l) { // Dirty color table
+                       uint32_t nnum = uaddr >> 4;
+                       color_ram[uaddr] = tval.w.l;
+                       if(color_cached[nnum]) {
+                               for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
+                                       if(cache_index[i].color == (uint16_t)(nnum + 256)) {
+                                               if((cache_index[i].is_use) && !(cache_index[i].is_32768)) {
+                                                       clear_cache(i);
+                                               }
                                        }
                                }
+                               color_cached[nnum] = false;
+
                        }
-                       color_cached[nnum] = false;
+               } else {
+                       color_ram[uaddr] = tval.w.l;
                }
                break;
        default:
                // ToDO: Discard cache
-               p8 = &(pattern_ram[(addr & 0x1ffff) - 0x4000]);
-               *p8 = (uint8_t)(data & 0xff);
-               if(pattern_cached[((addr & 0x1fffe) - 0x4000) >> 7]) {
-                       uint32_t nnum = ((addr & 0x1fffe) - 0x4000) >> 7;
-                       for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
-                               if(cache_index[i].num == (uint16_t)nnum) {
-                                       if(cache_index[i].is_use) {
-                                               clear_cache(i);
+               uaddr = (addr & 0x1ffff) - 0x4000;
+               p8 = &(pattern_ram[uaddr]);
+               tmp8 = *p8;
+               if(use_cache) {
+                       if((uint8_t)(data & 0xff) != tmp8) { // Dirty pattern memory.
+                               *p8 = (uint8_t)(data & 0xff);
+                               uint32_t nnum = uaddr >> 7;
+                               uint32_t nnum_bak = nnum;
+                               if(pattern_cached[nnum]) {  // ToDo: Search another number.
+                                       for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
+                                               if(cache_index[i].is_32768) {
+                                               if(cache_index[i].num == (uint16_t)nnum) {
+                                                       if(cache_index[i].is_use) {
+                                                               clear_cache(i);
+                                                       }
+                                               }
+                                       } else {
+                                               uint32_t begin;
+                                               uint32_t end;
+                                               uint32_t clen = 0;
+                                               // OK?
+                                               begin = (nnum <= (128 + 3)) ? (128 + 3) : nnum - 3;
+                                               end = (nnum <= 128) ? 128 : nnum + 3;
+                                               if(begin < 1024) {
+                                                       if(end > 1023) end = 1023;
+                                                       if((cache_index[i].num >= begin) && (cache_index[i].num <= end)) { 
+                                                               clen = end - begin + 1;
+                                                               for(uint32_t j = 0; j < clen; j++) {
+                                                                       if(cache_index[i].num == (uint16_t)(begin + j)) {
+                                                                               if(cache_index[i].is_use) {
+                                                                                       clear_cache(i);
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
                                        }
                                }
+                               pattern_cached[nnum] = false;
+                               }
                        }
-                       pattern_cached[((addr & 0x1fffe) - 0x4000) >> 7] = false;
-               }
+               } else {
+                       *p8 = (uint8_t)(data & 0xff);
+               }               
                break;
        }
        return;
@@ -502,65 +610,38 @@ void TOWNS_SPRITE::write_data8(uint32_t addr, uint32_t data)
 
 void TOWNS_SPRITE::write_data16(uint32_t addr, uint32_t data)
 {
-       uint32_t nbank;
-       uint16_t* p;
-       pair_t tval;
-       if((addr >= 0x81000000) && (addr < 0x81020000)) {
-               nbank = (addr & 0x1e000) >> 12;
-       } else {
-               nbank = 0; // OK?
-       }
-       switch(nbank) {
-       case 0:
-       case 1:
-               index_ram[(addr & 0x1ffe) >> 1] = (uint16_t)(data & 0xffff);
-               break;
-       case 2:
-       case 3:
-               // ToDO: Discard cache
-               color_ram[(addr & 0x1ffe) >> 1] = (uint16_t)(data & 0xffff);
-               if(color_cached[(addr & 0x1ffe) >> 5]) {
-                       uint32_t nnum = (addr & 0x1ffe) >> 5;
-                       for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
-                               if(cache_index[i].color == (uint16_t)(nnum + 256)) {
-                                       if(cache_index[i].is_use) {
-                                               clear_cache(i);
-                                       }
-                               }
-                       }
-                       color_cached[nnum] = false;
-               }
-               break;
-       default:
-               // ToDO: Discard cache
-               tval.w.l = (uint16_t)data;
-               pattern_ram[(addr & 0x1fffe) - 0x4000] = tval.b.l;              
-               pattern_ram[(addr & 0x1fffe) - 0x4000 + 1] = tval.b.h;
-               if(pattern_cached[((addr & 0x1fffe) - 0x4000) >> 7]) {
-                       uint32_t nnum = ((addr & 0x1fffe) - 0x4000) >> 7;
-                       for(int i = 0; i < TOWNS_SPRITE_CACHE_NUM; i++) {
-                               if(cache_index[i].num == (uint16_t)nnum) {
-                                       if(cache_index[i].is_use) {
-                                               clear_cache(i);
-                                       }
-                               }
-                       }
-                       pattern_cached[((addr & 0x1fffe) - 0x4000) >> 7] = false;
-               }
-               break;
-       }
-       return;
+       pair_t t;
+       t.d = data;
+       write_data8(addr, (uint32_t)(t.b.l));
+       write_data8(addr + 1, (uint32_t)(t.b.h));
 }
-
+                               
 void TOWNS_SPRITE::write_data32(uint32_t addr, uint32_t data)
 {
        pair_t t;
        t.d = data;
-       write_data16(addr, (uint32_t)(t.w.l));
-       if(addr < 0x8101fffe) write_data16(addr + 2, (uint32_t)(t.w.h));
+       write_data8(addr, (uint32_t)(t.b.l));
+       write_data8(addr + 1, (uint32_t)(t.b.h));
+       if(addr < 0x8101fffe) {
+               write_data8(addr + 2, (uint32_t)(t.b.h2));
+               write_data8(addr + 3, (uint32_t)(t.b.h3));
+       }
 }
 
-
+// Q: Is changing pages syncing to Frame?
+// ToDo: Implement VRAM.
+void FMTOWNS_SPRITE::write_signal(int id, uint32_t data, uint32_t mask)
+{
+       if(id == SIG_FMTOWNS_SPRITE_CACHE_ENABLE) {
+               cache_enabled = ((data & mask) != 0);
+       } else if(id == SIG_FMTOWNS_SPRITE_SWAP_BUFFER) {
+               write_page = display_page;
+               display_page = (displae_page + 1) & 1;
+       } else if(id == SIG_FMTOWNS_SPRITE_SET_DATA_VRAM) {
+       } else if(id == SIG_FMTOWNS_SPRITE_SET_MASK_VRAM) {
+       }
+       
+}
 #define STATE_VERSION  1
 
 #include "../../statesub.h"
@@ -578,8 +659,9 @@ void TOWNS_SPRITE::decl_state()
        DECL_STATE_ENTRY_UINT16(reg_hoffset);
        DECL_STATE_ENTRY_BOOL(disp_page0);
        DECL_STATE_ENTRY_BOOL(disp_page1);
-       
-       DECL_STATE_ENTRY_INT32(sprite_limit);
+
+       DECL_STATE_ENTRY_BOOL(use_cache);
+
        
        DECL_STATE_ENTRY_1D_ARRAY(index_ram, sizeof(index_ram) / sizeof(uint16_t));
        DECL_STATE_ENTRY_1D_ARRAY(pattern_ram, sizeof(pattern_ram) / sizeof(uint8_t));
index 26d0722..5c862bd 100644 (file)
@@ -30,7 +30,8 @@ class TOWNS_VRAM;
 
 class TOWNS_SPRITE : public DEVICE
 {
-private:
+
+protected:
        TOWNS_VRAM *vram_head;
 
        // REGISTERS
@@ -53,7 +54,19 @@ private:
 
        bool pattern_cached[((65536 - (4096 * 2)) * 2) / (8 * 16)];
        bool color_cached[256];
-protected:
+       
+       bool sprite_enabled;
+       bool use_cache;
+       inline void take_data_32768(uint16_t* src, uint16_t* dst, uint16_t* mask);
+       inline void take_data_32768_mirror(uint16_t* src, uint16_t* dst, uint16_t* mask);
+       inline void take_data_16(uint8_t* src, uint16_t* color_table, uint16_t* dst, uint16_t* mask);
+       inline void take_data_16_mirror(uint8_t* src, uint16_t* color_table, uint16_t* dst, uint16_t* mask);
+       inline void zoom_data(uint16_t* cache, uint16_t* maskcache, bool is_halfx, bool is_halfy, uint16_t* dstcache, uint16_t* dstmask);
+
+       void rotate_data_0(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768, bool is_halfx, bool is_halfy);
+       void rotate_data_90(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768, bool is_halfx, bool is_halfy);
+       void rotate_data_180(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768, bool is_halfx, bool is_halfy);
+       void rotate_data_270(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768, bool is_halfx, bool is_halfy);
 
        
 public:
@@ -86,1252 +99,329 @@ public:
        bool load_stste(FILEIO *fio);
 };
 
-inline void TOWNS_SPRITE::render_32768_x1_x1(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+inline void TOWNS_SPRITE::take_data_32768(uint16_t* src, uint16_t* dst, uint16_t* mask)
 {
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
-       }
-       uint16_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint16_t* yaddr;
-       uint16_t*p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(y - 15) << 5]); // 1 line is 4 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 5]); // 1 line is 4 bytes (16pixels)
-                       }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 15; i >= 0; i--) {
-                                       pixels[i] = p[15 - i];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 15; i++) {
-                                       pixels[i] = p[i];
-                               }
-                       }
-               } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[15 - y]);
-                       } else {
-                               yaddr = &(qp[y]);
-                       }                       
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 15; x >= 0; x--) {
-                                       p = &(yaddr[x << 5]);
-                                       pixels[x] = p[15 - y];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 15; x++) {
-                                       p = &(yaddr[x << 5]);
-                                       pixels[x] = p[y];
-                               }
-                       }
+       uint16_t* p = src;
+       uint16_t* q = dst;
+       uint16_t* r = mask;
+       for(int y = 0; y < 16; y++) {
+               for(int x = 0; x < 16; x++) {
+                       q[x] = p[x];
                }
-__DECL_VECTORIZED_LOOP         
                for(int x = 0; x < 16; x++) {
-                       masks[x] = ((pixels[x] & 0x8000) == 0) ? 0xffff : 0x0000;
-                       cp[x] = pixels[x];
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       pixels[x] = pixels[x] & masks[x];
-                       dp[x] = pixels[x] | tpixels[x];
+                       r[x] = ((q[x] & 0x8000) != 0) ? 0 : 0xffff;
                }
+               r += 16;
+               q += 16;
+               p += 16;
        }
 }
 
-inline void TOWNS_SPRITE::render_32768_x05_x1(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+inline void TOWNS_SPRITE::take_data_32768_mirror(uint16_t* src, uint16_t* dst, uint16_t* mask)
 {
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
-       }
-       uint16_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint16_t* yaddr;
-       uint16_t*p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(y - 15) << 5]); // 1 line is 4 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 5]); // 1 line is 4 bytes (16pixels)
-                       }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 7; i >= 0; i--) {
-                                       pixels[i] = p[15 - (i << 1)];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 7; i++) {
-                                       pixels[i] = p[i << 1];
-                               }
-                       }
-               } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[15 - y]);
-                       } else {
-                               yaddr = &(qp[y]);
-                       }                       
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 7; x >= 0; x--) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[15 - y];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 7; x++) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[y];
-                               }
-                       }
+       uint16_t* p = src;
+       uint16_t* q = dst;
+       uint16_t* r = mask;
+       for(int y = 0; y < 16; y++) {
+               for(int x = 0; x < 16; x++) {
+                       q[x] = p[15 - x];
                }
-__DECL_VECTORIZED_LOOP         
-               for(int x = 0; x < 8; x++) {
-                       masks[x] = ((pixels[x] & 0x8000) == 0) ? 0xffff : 0x0000;
-                       cp[x] = pixels[x];
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       pixels[x] = pixels[x] & masks[x];
-                       dp[x] = pixels[x] | tpixels[x];
+               for(int x = 0; x < 16; x++) {
+                       r[x] = ((q[x] & 0x8000) != 0) ? 0 : 0xffff;
                }
+               r += 16;
+               q += 16;
+               p += 16;
        }
 }
 
 
-inline void TOWNS_SPRITE::render_32768_x1_x05(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+inline void TOWNS_SPRITE::take_data_16(uint8_t* src, uint16_t* color_table, uint16_t* dst, uint16_t* mask)
 {
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
-       }
-       uint16_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint16_t* yaddr;
-       uint16_t*p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(7 - y) << 6]); // 1 line is 4 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 6]); // 1 line is 4 bytes (16pixels)
-                       }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 15; i >= 0; i--) {
-                                       pixels[i] = p[15 - i];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 15; i++) {
-                                       pixels[i] = p[i];
-                               }
-                       }
-               } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[15 - (y << 1)]);
-                       } else {
-                               yaddr = &(qp[y << 1]);
-                       }                       
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 7; x >= 0; x--) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[7 - y];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 7; x++) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[y];
-                               }
-                       }
+       uint8_t* p = src;
+       uint16_t* q = dst;
+       uint16_t* r = mask;
+       uint8_t cache[16];
+       for(int y = 0; y < 16; y++) {
+               for(int x = 0; x < 16; x += 2) {
+                       cache[x] = p[x >> 1];
+                       cache[x + 1] = cache[x];
+               }
+               for(int x = 0; x < 16; x += 2) {
+                       cache[x] = cache[x] >> 4;
                }
-__DECL_VECTORIZED_LOOP         
-               for(int x = 0; x < 8; x++) {
-                       masks[x] = ((pixels[x] & 0x8000) == 0) ? 0xffff : 0x0000;
-                       cp[x] = pixels[x];
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       pixels[x] = pixels[x] & masks[x];
-                       dp[x] = pixels[x] | tpixels[x];
+               for(int x = 0; x < 16; x++) {
+                       cache[x] = cache[x] & 0x0f;
+                       r[x] = (cache[x] == 0) ? 0x0000 : 0xffff;
+                       q[x] = color_table[cache[x]];
                }
+               r += 16;
+               q += 16;
+               p += 8;
        }
 }
 
-inline void TOWNS_SPRITE::render_32768_x05_x05(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+inline void TOWNS_SPRITE::take_data_16_mirror(uint8_t* src, uint16_t* color_table, uint16_t* dst, uint16_t* mask)
 {
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
-       }
-       uint16_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint16_t* yaddr;
-       uint16_t*p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(7 - y) << 6]); // 1 line is 8 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 6]); // 1 line is 8 bytes (16pixels)
-                       }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 7; i >= 0; i--) {
-                                       pixels[i] = p[15 - (i << 1)];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 7; i++) {
-                                       pixels[i] = p[i << 1];
-                               }
-                       }
-               } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[15 - (y << 1)]);
-                       } else {
-                               yaddr = &(qp[y << 1]);
-                       }                       
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 7; x >= 0; x--) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[7 - (y >> 1)];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 7; x++) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[y];
-                               }
-                       }
+       uint8_t* p = src;
+       uint16_t* q = dst;
+       uint16_t* r = mask;
+       uint8_t cache[16];
+       for(int y = 0; y < 16; y++) {
+               for(int x = 0; x < 16; x += 2) {
+                       cache[x] = p[(15 - x) >> 1];
+                       cache[x + 1] = cache[x];
+               }
+               for(int x = 1; x < 16; x += 2) {
+                       cache[x] = cache[x] >> 4;
                }
-__DECL_VECTORIZED_LOOP         
-               for(int x = 0; x < 8; x++) {
-                       masks[x] = ((pixels[x] & 0x8000) == 0) ? 0xffff : 0x0000;
-                       cp[x] = pixels[x];
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       pixels[x] = pixels[x] & masks[x];
-                       dp[x] = pixels[x] | tpixels[x];
+               for(int x = 0; x < 16; x++) {
+                       cache[x] = cache[x] & 0x0f;
+                       r[x] = (cache[x] == 0) ? 0x0000 : 0xffff;
+                       q[x] = color_table[cache[x]];
                }
+               r += 16;
+               q += 16;
+               p += 8;
        }
 }
 
 
-inline void TOWNS_SPRITE::render_16_x1_x1(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+void TOWNS_SPRITE::rotate_data_0(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768, bool is_halfx, bool is_halfy)
 {
-       uint8_t* qp = (uint8_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
-       }
-       uint8_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t tpixels2[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint8_t* yaddr;
-       uint8_t* p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(y - 15) << 3]); // 1 line is 4 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 3]); // 1 line is 4 bytes (16pixels)
-                       }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 15; i >= 0; i--) {
-                                       pixels[i] = p[(15 - i) >> 1];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 15; i++) {
-                                       pixels[i] = p[i];
-                               }
-                       }
-__DECL_VECTORIZED_LOOP
-                       for(int i = 0; i < 16; i+= 2) {
-                               pixels[i] = pixels[i] >> 4;
-                       }
-__DECL_VECTORIZED_LOOP
-                       for(int i = 0; i < 16; i++) {
-                               pixels[i] = pixels[i] & 0x0f;
-                       }
+       uint16_t cache[16 * 16];
+       if(!is_32768) {
+               if(is_mirror) {
+                       take_data_16_mirror(src, color_table, cache, mask);
                } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[(15 - y) >> 1]);
-                       } else {
-                               yaddr = &(qp[(y >> 1)]);
-                       }                       
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 15; x >= 0; x--) {
-                                       p = &(yaddr[x << 3]);
-                                       pixels[x] = p[(15 - y) >> 1];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 15; x++) {
-                                       p = &(yaddr[x << 3]);
-                                       pixels[x] = p[y >> 1];
-                               }
-                       }
-__DECL_VECTORIZED_LOOP
-                       for(int i = 0; i < 16; i++) {
-                               pixels[i] = pixels[i] >> 4;
-                               pixels[i] = pixels[i] & 0x0f;
-                       }
-                       
+                       take_data_16(src, color_table, cache, mask);
                }
-__DECL_VECTORIZED_LOOP         
-               for(int x = 0; x < 16; x++) {
-                       masks[x] = (pixels[x] == 0) ? 0xffff : 0x0000
-                       tpixel[x] = color_index[pixels[x]];
-                       cp[x] = tpixel;
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels2[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       tpixels[x] = tpixels[x] & masks[x];
-                       dp[x] = tpixels[x] | tpixels2[x];
+               
+       } else {
+               if(is_mirror) {
+                       take_data_32768_mirror((uint16_t*)src, cache, mask);
+               } else {
+                       take_data_16((uint16_t*)src, cache, mask);
                }
        }
+       // Rotate
+       // Zoom
+       uint16_t maskcache[16 * 16];
+       memcpy(maskcache, mask, sizeof(maskcache));
+       zoom_data(cache, maskcache, is_halfx, is_halfy, dstcache, mask);
 }
 
-inline void TOWNS_SPRITE::render_16_x05_x1(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+void TOWNS_SPRITE::rotate_data_90(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768, bool is_halfx, bool is_halfy)
 {
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 2;
-                       ybegin = 0;
-                       yend = 16;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
-       }
-       uint16_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint8_t* yaddr;
-       uint8_t*p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(y - 15) << 3]); // 1 line is 4 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 3]); // 1 line is 4 bytes (16pixels)
-                       }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 7; i >= 0; i--) {
-                                       pixels[i] = p[7 - i];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 7; i++) {
-                                       pixels[i] = p[i];
-                               }
-                       }
-__DECL_VECTORIZED_LOOP
-                       for(int i = 0; i < 8; i+= 2) {
-                               pixels[i] = pixels[i] >> 4;
-                               pixels[i] = pixels[i] & 0x0f;
-                       }
+       uint16_t cache[16 * 16];
+       if(!is_32768) {
+               if(is_mirror) {
+                       take_data_16_mirror(src, color_table, cache, mask);
                } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[(15 - y) >> 1]);
-                       } else {
-                               yaddr = &(qp[y >> 1]);
-                       }                       
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 7; x >= 0; x--) {
-                                       p = &(yaddr[x << 4]);
-                                       pixels[x] = p[15 - y];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 7; x++) {
-                                       p = &(yaddr[x << 4]);
-                                       pixels[x] = p[y];
-                               }
-                       }
-__DECL_VECTORIZED_LOOP
-                       for(int i = 0; i < 8; i++) {
-                               pixels[i] = pixels[i] >> 4;
-                               pixels[i] = pixels[i] & 0x0f;
-                       }
+                       take_data_16(src, color_table, cache, mask);
                }
-__DECL_VECTORIZED_LOOP         
-               for(int x = 0; x < 8; x++) {
-                       masks[x] = ((pixels[x] & 0x8000) == 0) ? 0xffff : 0x0000;
-                       cp[x] = pixels[x];
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       pixels[x] = pixels[x] & masks[x];
-                       dp[x] = pixels[x] | tpixels[x];
+               
+       } else {
+               if(is_mirror) {
+                       take_data_32768_mirror((uint16_t*)src, cache, mask);
+               } else {
+                       take_data_16((uint16_t*)src, cache, mask);
                }
        }
+       // Rotate
+       uint16_t maskcache[16][16];
+       uint16_t cache2[16][16];
+       if(is_mirror) {
+               // q[x][y] = p[15 - y][15 - x]
+__DECL_VECTORIZED_LOOP                         
+               for(y = 0; y < 16; y++) {
+                       uint16_t* p = &(cache[15 - y]); 
+                       uint16_t* q = &(mask[15 - y]); 
+                       for(x = 0; x < 16; x++) {
+                               cache2[y][x] = p[(15 - x) << 4];
+                               maskcache[y][x] = q[(15 - x) << 4];
+                       }
+               }                       
+       } else {
+               // q[x][y] = p[15 - y][x]
+               for(y = 0; y < 16; y++) {
+                       uint16_t* p = &(cache[15 - y]);
+                       uint16_t* q = &(mask[15 - y]);
+__DECL_VECTORIZED_LOOP                                 
+                       for(x = 0; x < 16; x++) {
+                               cache2[y][x] = p[x << 4];
+                               maskcache[y][x] = q[x << 4];
+                       }
+               }                       
+       }       
+       zoom_data((uint16_t*)(&(cache2[0][0])), (uint16_t*)(&(maskcache[0][0])), is_halfx, is_halfy, dstcache, mask);
 }
 
-
-inline void TOWNS_SPRITE::render_16_x1_x05(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+void TOWNS_SPRITE::rotate_data_180(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768, bool is_halfx, bool is_halfy)
 {
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 16;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
+       uint16_t cache[16 * 16];
+       if(!is_32768) {
+               if(is_mirror) {
+                       take_data_16_mirror(src, color_table, cache, mask);
+               } else {
+                       take_data_16(src, color_table, cache, mask);
+               }
+               
+       } else {
+               if(is_mirror) {
+                       take_data_32768_mirror((uint16_t*)src, cache, mask);
+               } else {
+                       take_data_16((uint16_t*)src, cache, mask);
+               }
        }
-       uint16_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint16_t* yaddr;
-       uint16_t*p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(7 - y) << 6]); // 1 line is 4 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 6]); // 1 line is 4 bytes (16pixels)
+       // Rotate
+       uint16_t maskcache[16][16];
+       uint16_t cache2[16][16];
+       if(is_mirror) {
+               // q[x][y] = p[x][15 - y]
+               for(y = 0; y < 16; y++) {
+                       uint16_t* p = &(cache[(15 - y) << 4]); 
+                       uint16_t* q = &(mask[(15 - y) << 4]);
+__DECL_VECTORIZED_LOOP                                 
+                       for(x = 0; x < 16; x++) {
+                               cache2[y][x] = p[x];
+                               maskcache[y][x] = q[x];
                        }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 15; i >= 0; i--) {
-                                       pixels[i] = p[15 - i];
-                               }
-                       } else {
+               }                       
+       } else {
+               // q[x][y] = p[15 - x][15 - y]
+               for(y = 0; y < 16; y++) {
+                       uint16_t* p = &(cache[15 - y] << 4); 
+                       uint16_t* q = &(mask[15 - y] << 4);
 __DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 15; i++) {
-                                       pixels[i] = p[i];
-                               }
+                       for(x = 0; x < 16; x++) {
+                               cache2[y][x] = p[15 - x];
+                               maskcache[y][x] = q[15 - x];
                        }
+               }                       
+       }       
+       zoom_data((uint16_t*)(&(cache2[0][0])), (uint16_t*)(&(maskcache[0][0])), is_halfx, is_halfy, dstcache, mask);
+}
+
+void TOWNS_SPRITE::rotate_data_270(uint16_t* src, bool is_mirror, uint16_t* color_table, uint16_t* dstcache, uint16_t* mask, bool is_32768,bool is_halfx, bool is_halfy)
+{
+       uint16_t cache[16 * 16];
+       if(!is_32768) {
+               if(is_mirror) {
+                       take_data_16_mirror(src, color_table, cache, mask);
                } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[15 - (y << 1)]);
-                       } else {
-                               yaddr = &(qp[y << 1]);
-                       }                       
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 7; x >= 0; x--) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[7 - y];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 7; x++) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[y];
-                               }
-                       }
+                       take_data_16(src, color_table, cache, mask);
                }
-__DECL_VECTORIZED_LOOP         
-               for(int x = 0; x < 8; x++) {
-                       masks[x] = ((pixels[x] & 0x8000) == 0) ? 0xffff : 0x0000;
-                       cp[x] = pixels[x];
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       pixels[x] = pixels[x] & masks[x];
-                       dp[x] = pixels[x] | tpixels[x];
+               
+       } else {
+               if(is_mirror) {
+                       take_data_32768_mirror((uint16_t*)src, cache, mask);
+               } else {
+                       take_data_16((uint16_t*)src, cache, mask);
                }
        }
+       // Rotate
+       uint16_t maskcache[16][16];
+       uint16_t cache2[16][16];
+       if(is_mirror) {
+               // q[x][y] = p[y][x]
+               
+               for(y = 0; y < 16; y++) {
+                       uint16_t* p = &(cache[y]); 
+                       uint16_t* q = &(mask[y]);
+__DECL_VECTORIZED_LOOP                 
+                       for(x = 0; x < 16; x++) {
+                               cache2[y][x] = p[x << 4];
+                               maskcache[y][x] = q[x << 4];
+                       }
+               }                       
+       } else {
+               // q[x][y] = p[y][15 - x]
+               for(y = 0; y < 16; y++) {
+                       uint16_t* p = &(cache[15 - y]); 
+                       uint16_t* q = &(mask[15 - y]);
+__DECL_VECTORIZED_LOOP                 
+                       for(x = 0; x < 16; x++) {
+                               cache2[y][x] = p[x << 4];
+                               maskcache[y][x] = q[x << 4];
+                       }
+               }                       
+       }       
+       zoom_data((uint16_t*)(&(cache2[0][0])), (uint16_t*)(&(maskcache[0][0])), is_halfx, is_halfy, dstcache, mask);
 }
 
-inline void TOWNS_SPRITE::render_16_x05_x05(int num, uint16_t* dst, int rot_type, bool is_mirror, int stride)
+inline void TOWNS_SPRITE::zoom_data(uint16_t* cache, uint16_t* maskcache, bool is_halfx, bool is_halfy, uint16_t* dstcache, uint16_t* dstmask)
 {
-       uint16_t* qp = (uint16_t*)(sprite_table[num].pixels);
-       uint16_t *cache_pixel = &(cache_pixels[last_put_cache_num][0]);
-       uint16_t *cache_mask = cache_masks[last_put_cache_num][0];
-       int xbegin;
-       int xend;
-       int xstep;
-       int ybegin;
-       int yend;
-       int ystep;
-       int addr_base;
-       int addr_inc;
-       bool xreverse;
-       bool yreverse;
-       bool rotate = false;
-       switch(rot_type) {
-       case ROT_FMTOWNS_SPRITE_0:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = false;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = true;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_90:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = false;
-                       yreverse = true;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_180:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = true;
-                       rotate = false;
-                       if(is_mirror) {
-                               xreverse = false;
-                       }
-               }                       
-               break;
-       case ROT_FMTOWNS_SPRITE_270:
-                       xbegin = 0;
-                       xend = 8;
-                       xstep = 1;
-                       ybegin = 0;
-                       yend = 8;
-                       ystep = 1;
-                       xreverse = true;
-                       yreverse = false;
-                       rotate = true;
-                       if(is_mirror) {
-                               yreverse = true;
-                       }
-               }                       
-               break;
-       }
-       uint16_t pixels[16];
-       uint16_t masks[16];
-       uint16_t tpixels[16];
-       uint16_t* cp;
-       uint16_t* cm;
-       uint16* dp;
-       uint16_t* yaddr;
-       uint16_t*p;
-       for(y = ybegin; y != yend; y += ystep) {
-               cp = &(cache_pixel[y << 5]);
-               cm = &(cache_mask[y << 5]);
-               dp =  &(dst[stride * y]);
-               if(!rotate) {
-                       if(yreverse) {
-                               yaddr = &(qp[(7 - y) << 6]); // 1 line is 4 bytes (16pixels)
-                       } else {
-                               yaddr = &(qp[y << 6]); // 1 line is 4 bytes (16pixels)
-                       }
-                       p = &(yaddr[0]);
-                       if(xreverse) {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 7; i >= 0; i--) {
-                                       pixels[i] = p[15 - (i << 1)];
-                               }
-                       } else {
-__DECL_VECTORIZED_LOOP
-                               for(int i = 0; i <= 7; i++) {
-                                       pixels[i] = p[i << 1];
+       if(is_halfx) {
+               if(is_halfy) {
+                       uint16_t cache2[8][8];
+                       uint16_t maskcache2[8][8];
+                       for(int y = 0; y < 16; y += 2) {
+                               uint16_t cacheline[8];
+                               uint16_t *pp = &(cache[y << 4]);
+                               uint16_t maskcacheline[8];
+                               uint16_t *pq = &(maskcache[y << 4]);
+__DECL_VECTORIZED_LOOP                         
+                               for(int x = 0; x < 8; x++) {
+                                       cacheline[x] = pp[x << 1];
+                                       maskcacheline[x] = pq[x << 1];
                                }
-                       }
-               } else {
-                       // Rotate: Swap x, y
-                       if(yreverse) {
-                               yaddr = &(qp[15 - (y << 1)]);
-                       } else {
-                               yaddr = &(qp[y << 1]);
-                       }                       
-                       if(xreverse) {
 __DECL_VECTORIZED_LOOP                         
-                               for(int x = 7; x >= 0; x--) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[7 - x];
+                               for(int x = 0; x < 8; x++) {
+                                       cache2[y >> 1][x] = cacheline[x];
+                                       maskcache2[y >> 1][x] = maskcacheline[x];
+                               }
+                       }
+                       memcpy(dstcache, &(cache2[0][0]), 8 * 8 * sizeof(uint16_t));
+                       memcpy(dstmask, &(maskcache2[0][0]), 8 * 8 * sizeof(uint16_t));
+               } else { // halfx only, not halfy
+                       uint16_t cache2[16][8];
+                       uint16_t maskcache2[16][8];
+                       for(int y = 0; y < 16; y++) {
+                               uint16_t cacheline[8];
+                               uint16_t *pp = &(cache[y << 4]);
+                               uint16_t maskcacheline[8];
+                               uint16_t *pq = &(maskcache[y << 4]);
+__DECL_VECTORIZED_LOOP                         
+                               for(int x = 0; x < 8; x++) {
+                                       cacheline[x] = pp[x << 1];
+                                       maskcacheline[x] = pq[x << 1];
                                }
-                       } else {
 __DECL_VECTORIZED_LOOP                         
-                               for(int x = 0; x <= 7; x++) {
-                                       p = &(yaddr[x << 6]);
-                                       pixels[x] = p[x];
+                               for(int x = 0; x < 8; x++) {
+                                       cache2[y][x] = cacheline[x];
+                                       maskcache2[y][x] = maskcacheline[x];
                                }
                        }
+                       memcpy(dstcache, &(cache2[0][0]), 16 * 8 * sizeof(uint16_t));
+                       memcpy(mask, &(maskcache2[0][0]), 16 * 8 * sizeof(uint16_t));
                }
-__DECL_VECTORIZED_LOOP         
-               for(int x = 0; x < 8; x++) {
-                       masks[x] = ((pixels[x] & 0x8000) == 0) ? 0xffff : 0x0000;
-                       cp[x] = pixels[x];
-                       cm[x] = masks[x];
-                       // Draw to buffer
-                       tpixels[x] = dp[x] & masks[x];
-                       masks[x] = ~masks[x];
-                       pixels[x] = pixels[x] & masks[x];
-                       dp[x] = pixels[x] | tpixels[x];
-               }
-       }
-}
-
-
-inline void TOWNS_SPRITE::render_base(int num, uint16* dst_pixel, int width, int height, int stride)
-{
-       int half_type = 0;
-       int rot_type;
-       half_type = half_type | ((cache_index[num].is_halfx) ? 1 : 0);
-       half_type = half_type | ((cache_index[num].is_halfy) ? 2 : 0);
-
-       switch((sprite_table[num].rotate) & 7) {
-       case 0:
-               rot_type = ROT_FMTOWNS_SPRITE_0;
-               is_mirror = false;
-               break;
-       case 1:
-               rot_type = ROT_FMTOWNS_SPRITE_180;
-               is_mirror = true;
-               break;
-       case 2:
-               rot_type = ROT_FMTOWNS_SPRITE_180;
-               is_mirror = false;
-               break;
-       case 3:
-               rot_type = ROT_FMTOWNS_SPRITE_0;
-               is_mirror = true;
-               break;
-       case 4:
-               rot_type = ROT_FMTOWNS_SPRITE_270;
-               is_mirror = true;
-               break;
-       case 5:
-               rot_type = ROT_FMTOWNS_SPRITE_90;
-               is_mirror = false;
-               break;
-       case 6:
-               rotate = false;
-               rot_type = ROT_FMTOWNS_SPRITE_270;
-               is_mirror = false;
-               break;
-       case 7:
-               rot_type = ROT_FMTOWNS_SPRITE_90;
-               is_mirror = true;
-               break;
-       }
-       if(sprite_table[num].is_32768) {
-       switch(half_type & 3) {
-       case 0: // not rotate
-               render_32768_x1_x1(num, dst, rot_type, mirror, stride);
-               break;
-       case 1:
-               render_32768_x05_x1(num, dst, rot_type, mirror, stride);
-               break;
-       case 2:
-               render_32768_x1_x05(num, dst, rot_type, mirror, stride);
-               break;
-       case 3:
-               render_32768_x05_x05(num, dst, rot_type, mirror, stride);
-               break;
-       }
        } else {
-       switch(half_type & 3) {
-       case 0: // not rotate
-               render_16_x1_x1(num, dst, rot_type, mirror, stride);
-               break;
-       case 1:
-               render_16_x05_x1(num, dst, rot_type, mirror, stride);
-               break;
-       case 2:
-               render_16_x1_x05(num, dst, rot_type, mirror, stride);
-               break;
-       case 3:
-               render_16_x05_x05(num, dst, rot_type, mirror, stride);
-               break;
-       }
+               if(is_halfy) { // halfx only, not halfx
+                       uint16_t cache2[16][8];
+                       uint16_t maskcache2[16][8];
+                       for(int y = 0; y < 16; y += 2) {
+                               uint16_t cacheline[16];
+                               uint16_t *pp = &(cache[y << 4]);
+                               uint16_t maskcacheline[16];
+                               uint16_t *pq = &(maskcache[y << 4]);
+__DECL_VECTORIZED_LOOP
+                               for(int x = 0; x < 16; x++) {
+                                       cacheline[x] = pp[x];
+                                       maskcacheline[x] = pq[x];
+                               }
+__DECL_VECTORIZED_LOOP
+                               for(int x = 0; x < 16; x++) {
+                                       cache2[y >> 1][x] = cacheline[x];
+                                       maskcache2[y >> 1][x] = maskcacheline[x];
+                               }
+                       }
+                       memcpy(dstcache, &(cache2[0][0]), 8 * 16 * sizeof(uint16_t));
+                       memcpy(dstmask, &(maskcache2[0][0]), 8 * 16 * sizeof(uint16_t));
+               } else { // 1x1
+                       memcpy(dstcache, cache, 16 * 16 * sizeof(uint16_t));
+                       memcpy(dstmask, maskcache, 16 * 16 * sizeof(uint16_t));
+               }
        }
 }