00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../stdafx.h"
00013 #include "../core/alloc_func.hpp"
00014 #include "../zoom_func.h"
00015 #include "../core/math_func.hpp"
00016 #include "32bpp_optimized.hpp"
00017
00018 static const int MAX_PALETTE_TABLES = 50;
00019
00020 struct RecolourTable {
00021 SpriteID id;
00022 Colour tables[256];
00023 } _rgb_palettes[MAX_PALETTE_TABLES] = {{0,{{0}}}};
00024
00025 Colour _rgb_stringremap[3] = {{0}};
00026
00027 static FBlitter_32bppOptimized iFBlitter_32bppOptimized;
00028
00036 template <BlitterMode mode>
00037 inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom)
00038 {
00039 const SpriteData *src = (const SpriteData *)bp->sprite;
00040
00041
00042
00043 zoom = ZOOM_LVL_BEGIN;
00044 const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
00045
00046
00047
00048 const uint8 *src_n = (const uint8 *)(src->data + src->offset[zoom][1]);
00049
00050
00051 for (uint i = bp->skip_top; i != 0; i--) {
00052 src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
00053 src_n += *(uint32 *)src_n;
00054 }
00055
00056
00057 uint32 *dst = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left;
00058
00059
00060 const Colour *remap = (const Colour *)bp->remap;
00061 for (int y = 0; y < bp->height; y++) {
00062
00063 uint32 *dst_ln = dst + bp->pitch;
00064
00065
00066 const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px);
00067 src_px++;
00068
00069
00070 const uint8 *src_n_ln = src_n + *(uint32 *)src_n;
00071 src_n += 4;
00072
00073
00074 uint32 *dst_end = dst + bp->skip_left;
00075
00076
00077 uint n;
00078
00079 while (dst < dst_end) {
00080 n = *src_n++;
00081
00082 if (src_px->a == 0) {
00083 dst += n;
00084 src_px ++;
00085 src_n++;
00086 } else {
00087 if (dst + n > dst_end) {
00088 uint d = dst_end - dst;
00089 src_px += d;
00090 src_n += d;
00091
00092 dst = dst_end - bp->skip_left;
00093 dst_end = dst + bp->width;
00094
00095 n = min<uint>(n - d, (uint)bp->width);
00096 goto draw;
00097 }
00098 dst += n;
00099 src_px += n;
00100 src_n += n;
00101 }
00102 }
00103
00104 dst -= bp->skip_left;
00105 dst_end -= bp->skip_left;
00106
00107 dst_end += bp->width;
00108
00109 while (dst < dst_end) {
00110 n = min<uint>(*src_n++, (uint)(dst_end - dst));
00111
00112 if (src_px->a == 0) {
00113 dst += n;
00114 src_px++;
00115 src_n++;
00116 continue;
00117 }
00118
00119 draw:;
00120
00121 switch (mode) {
00122 case BM_COLOUR_REMAP:
00123 do {
00124 uint m = *src_n;
00125
00126 if (m == 0) {
00127 if (src_px->a == 255) {
00128 *dst = src_px->data;
00129 } else {
00130 *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
00131 }
00132 } else {
00133 Colour r = remap[m];
00134 if (r.a != 0) {
00135 uint src_col = ComposeColour(src_px->a, src_px->r, src_px->g, src_px->b);
00136 uint comp_col = ComposeColourBlend(r.data, src_col);
00137 *dst = ComposeColourPA(comp_col, src_px->a, *dst);
00138 }
00139 }
00140 dst++;
00141 src_px++;
00142 src_n++;
00143 } while (--n != 0);
00144 break;
00145 case BM_COLOUR_OPAQUE:
00146 do {
00147 uint m = *src_n;
00148
00149 if (m == 0) {
00150 *dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
00151 } else {
00152 Colour r = remap[m];
00153 if (r.a != 0) {
00154 *dst = ComposeColourPA(r.data, src_px->a, *dst);
00155 }
00156 }
00157 dst++;
00158 src_px++;
00159 src_n++;
00160 } while (--n != 0);
00161 break;
00162 case BM_TRANSPARENT:
00163 do {
00164 uint m = *src_n;
00165 if (m == 0) {
00166 *dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a / 2, *dst);
00167 } else {
00168 if (remap){
00169 Colour r = remap[m];
00170 if (r.a != 0) *dst = ComposeColourPA(r.data, src_px->a / 2, *dst);
00171 }
00172 else {
00173 *dst = ComposeColourRGBA(src_px->r, src_px->g, src_px->b, src_px->a / 2, *dst);
00174 }
00175 }
00176
00177 dst++;
00178 src_px++;
00179 src_n++;
00180
00181
00182
00183 } while (--n != 0);
00184 break;
00185 case BM_SHADOW:
00186
00187 src_n += n;
00188 if (src_px->a == 255) {
00189 src_px += n;
00190 do {
00191 *dst = MakeTransparent(*dst, 3, 4);
00192 dst++;
00193 } while (--n != 0);
00194 } else {
00195 do {
00196 *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4);
00197 dst++;
00198 src_px++;
00199 } while (--n != 0);
00200 }
00201
00202 break;
00203 default:
00204 if (src_px->a == 255) {
00205
00206 src_n += n;
00207 do {
00208 *dst = src_px->data;
00209 dst++;
00210 src_px++;
00211 } while (--n != 0);
00212 } else {
00213 src_n += n;
00214 do {
00215 *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst);
00216 dst++;
00217 src_px++;
00218 } while (--n != 0);
00219 }
00220 break;
00221 }
00222 }
00223 dst = dst_ln;
00224 src_px = src_px_ln;
00225 src_n = src_n_ln;
00226 }
00227 }
00228
00236 void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom)
00237 {
00238 switch (mode) {
00239 default: NOT_REACHED();
00240 case BM_NORMAL: Draw<BM_NORMAL> (bp, zoom); return;
00241 case BM_COLOUR_REMAP: Draw<BM_COLOUR_REMAP> (bp, zoom); return;
00242 case BM_COLOUR_OPAQUE: Draw<BM_COLOUR_OPAQUE>(bp, zoom); return;
00243 case BM_TRANSPARENT: Draw<BM_TRANSPARENT> (bp, zoom); return;
00244 case BM_SHADOW: Draw<BM_SHADOW> (bp, zoom); return;
00245 }
00246 }
00247
00255 static const SpriteLoader::Sprite *ResizeSprite(const SpriteLoader::Sprite *sprite_src, ZoomLevel zoom)
00256 {
00257 return sprite_src;
00258 }
00259
00260 Sprite *Blitter_32bppOptimized::Encode(SpriteLoader::Sprite *sprite, AllocatorProc *allocator)
00261 {
00262
00263
00264
00265 Colour *dst_px_orig[ZOOM_LVL_COUNT];
00266
00267
00268
00269
00270
00271
00272
00273 uint8 *dst_n_orig[ZOOM_LVL_COUNT];
00274
00275
00276 uint32 lengths[ZOOM_LVL_COUNT][2];
00277
00278 for (ZoomLevel z = ZOOM_LVL_BEGIN; z <= ZOOM_LVL_BEGIN; z++) {
00279 const SpriteLoader::Sprite *src_orig = ResizeSprite(sprite, z);
00280
00281 uint size = src_orig->height * src_orig->width;
00282
00283 dst_px_orig[z] = CallocT<Colour>(size + src_orig->height * 2);
00284 dst_n_orig[z] = CallocT<uint8>(size * 2 + src_orig->height * 4 * 2);
00285
00286 uint32 *dst_px_ln = (uint32 *)dst_px_orig[z];
00287 uint32 *dst_n_ln = (uint32 *)dst_n_orig[z];
00288
00289 const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *)src_orig->data;
00290
00291 for (uint y = src_orig->height; y > 0; y--) {
00292 Colour *dst_px = (Colour *)(dst_px_ln + 1);
00293 uint8 *dst_n = (uint8 *)(dst_n_ln + 1);
00294
00295 uint8 *dst_len = dst_n++;
00296
00297 uint last = 3;
00298 int len = 0;
00299
00300 for (uint x = src_orig->width; x > 0; x--) {
00301 uint8 a = src->a;
00302 uint t = a > 0 && a < 255 ? 1 : a;
00303
00304 if (last != t || len == 255) {
00305 if (last != 3) {
00306 *dst_len = len;
00307 dst_len = dst_n++;
00308 }
00309 len = 0;
00310 }
00311
00312 last = t;
00313 len++;
00314
00315 if (a != 0) {
00316 dst_px->a = a;
00317 *dst_n = src->m;
00318
00319 dst_px->r = src->r;
00320 dst_px->g = src->g;
00321 dst_px->b = src->b;
00322
00323 dst_px++;
00324 dst_n++;
00325 } else if (len == 1) {
00326 dst_px++;
00327 *dst_n = src->m;
00328 dst_n++;
00329 }
00330
00331 src++;
00332 }
00333
00334 if (last != 3) {
00335 *dst_len = len;
00336 }
00337
00338 dst_px = (Colour *)AlignPtr(dst_px, 4);
00339 dst_n = (uint8 *)AlignPtr(dst_n, 4);
00340
00341 *dst_px_ln = (uint8 *)dst_px - (uint8 *)dst_px_ln;
00342 *dst_n_ln = (uint8 *)dst_n - (uint8 *)dst_n_ln;
00343
00344 dst_px_ln = (uint32 *)dst_px;
00345 dst_n_ln = (uint32 *)dst_n;
00346 }
00347
00348 lengths[z][0] = (byte *)dst_px_ln - (byte *)dst_px_orig[z];
00349 lengths[z][1] = (byte *)dst_n_ln - (byte *)dst_n_orig[z];
00350
00351 }
00352
00353 uint len = 0;
00354 for (ZoomLevel z = ZOOM_LVL_BEGIN; z <= ZOOM_LVL_BEGIN; z++) {
00355 len += lengths[z][0] + lengths[z][1];
00356 }
00357
00358 Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + sizeof(SpriteData) + len);
00359
00360 dest_sprite->height = sprite->height;
00361 dest_sprite->width = sprite->width;
00362 dest_sprite->x_offs = sprite->x_offs;
00363 dest_sprite->y_offs = sprite->y_offs;
00364
00365 SpriteData *dst = (SpriteData *)dest_sprite->data;
00366
00367 ZoomLevel z = ZOOM_LVL_BEGIN;
00368 dst->offset[z][0] = 0;
00369 dst->offset[z][1] = lengths[z][0] + dst->offset[z][0];
00370
00371 memcpy(dst->data + dst->offset[z][0], dst_px_orig[z], lengths[z][0]);
00372 memcpy(dst->data + dst->offset[z][1], dst_n_orig[z], lengths[z][1]);
00373
00374 free(dst_px_orig[z]);
00375 free(dst_n_orig[z]);
00376
00377 return dest_sprite;
00378 }
00379
00380 void Blitter_32bppOptimized::RescaleSpriteHalfSize(const SpriteLoader::Sprite *src_sprite,
00381 SpriteLoader::Sprite *dest_sprite,
00382 bool prevent_alpha_bleeding)
00383 {
00384 SpriteLoader::CommonPixel *dst;
00385 SpriteLoader::CommonPixel *src;
00386 int width, height;
00387 int x, y;
00388 bool extra_px_x = false;
00389 bool extra_px_y = false;
00390
00391 SpriteLoader::CommonPixel clr;
00392
00393 width = (src_sprite->width + 1) / 2;
00394 height = (src_sprite->height + 1) / 2;
00395
00396
00397 if (src_sprite->width & 1) {
00398 extra_px_x = true;
00399 }
00400
00401 if (src_sprite->height & 1) {
00402 extra_px_y = true;
00403 }
00404
00405
00406 dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
00407 dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
00408 src = (SpriteLoader::CommonPixel *)src_sprite->data;
00409
00410 dest_sprite->width = width ;
00411 dest_sprite->height = height;
00412
00413 dest_sprite->x_offs = src_sprite->x_offs / 2;
00414 dest_sprite->y_offs = src_sprite->y_offs / 2;
00415
00416 for (y = 0; y < height + (extra_px_y ? -1 : 0); y++) {
00417 for (x = 0; x < width + (extra_px_x ? -1 : 0); x++) {
00418 uint ma = 0;
00419 uint a = 0;
00420 uint r = 0;
00421 uint g = 0;
00422 uint b = 0;
00423 uint i;
00424 uint j;
00425
00426 for (i = 0; i < 2; i++) {
00427 for (j = 0; j < 2; j++) {
00428 uint ca;
00429 uint cr;
00430 uint cg;
00431 uint cb;
00432
00433 clr = src[((2 * y + i ) * src_sprite->width) + (2 * x + j )];
00434 ca = clr.a;
00435 cr = clr.r;
00436 cg = clr.g;
00437 cb = clr.b;
00438
00439 a += ca;
00440 r += ca * cr;
00441 g += ca * cg;
00442 b += ca * cb;
00443 if (prevent_alpha_bleeding) {
00444 if (ca > ma) ma = ca;
00445 } else {
00446 ma += ca;
00447 }
00448 }
00449 }
00450
00451 if (a == 0) {
00452 dst[y * width + x].r = 0;
00453 dst[y * width + x].g = 0;
00454 dst[y * width + x].b = 0;
00455 dst[y * width + x].a = 0;
00456 dst[y * width + x].m = 0;
00457 } else {
00458 r /= a;
00459 g /= a;
00460 b /= a;
00461 if (prevent_alpha_bleeding) {
00462 a = ma;
00463 } else {
00464 a /= 4;
00465 }
00466 dst[y * width + x].r = r;
00467 dst[y * width + x].g = g;
00468 dst[y * width + x].b = b;
00469 dst[y * width + x].a = a;
00470 dst[y * width + x].m = clr.m;
00471 }
00472 }
00473 if (extra_px_x) {
00474 clr = src[((2 * y ) * src_sprite->width) + (2 * x)];
00475 dst[y * width + x] = clr;
00476 }
00477 }
00478
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 void Blitter_32bppOptimized::RescaleSpriteDoubleSize(const SpriteLoader::Sprite *src_sprite,
00583 SpriteLoader::Sprite *dest_sprite)
00584 {
00585 int width, height;
00586 SpriteLoader::CommonPixel *dst;
00587 SpriteLoader::CommonPixel *src;
00588
00589 width = src_sprite->width * 2;
00590 height = src_sprite->height * 2;
00591
00592 dest_sprite->data = CallocT<SpriteLoader::CommonPixel>(height * width);
00593 dst = (SpriteLoader::CommonPixel *)dest_sprite->data;
00594 src = (SpriteLoader::CommonPixel *)src_sprite->data;
00595
00596 dest_sprite->width = width;
00597 dest_sprite->height = height;
00598 dest_sprite->x_offs = src_sprite->x_offs * 2;
00599 dest_sprite->y_offs = src_sprite->y_offs * 2;
00600 SpriteLoader::CommonPixel B, D, E, H, F;
00601 SpriteLoader::CommonPixel E0, E1, E2, E3;
00602 uint dst_y = 0;
00603 uint src_y_idx = 0;
00604 for (int y = 0; y < src_sprite->height ; y++) {
00605 int x;
00606
00607 uint dst_x = 0;
00608 for (x = 0; x < src_sprite->width - 1; x++) {
00609 E = src[src_y_idx + x];
00610 if (src_y_idx) {
00611 B = src[src_y_idx + x - src_sprite->width];
00612 } else {
00613 B = src[src_y_idx + x];
00614 }
00615 if (x) {
00616 D = src[src_y_idx + x - 1];
00617 } else {
00618 D = src[src_y_idx + x ];
00619 }
00620 if (x < src_sprite->width - 1){
00621 F = src[src_y_idx + x + 1];
00622 } else {
00623 F = src[src_y_idx + x ];
00624 }
00625 if (y < src_sprite->height - 1){
00626 H = src[src_y_idx + x + src_sprite->width];
00627 } else {
00628 H = src[src_y_idx + x];
00629 }
00630 if ((B.r != H.r && D.r != F.r) ||
00631 (B.g != H.g && D.g != F.g) ||
00632 (B.b != H.b && D.b != F.b) ||
00633 (B.a != H.a && D.a != F.a))
00634 {
00635 if ((D.r == B.r) &&
00636 (D.g == B.g) &&
00637 (D.b == B.b) &&
00638 (D.a == B.a)) {
00639 E0 = D;
00640 } else {
00641 E0 = E;
00642 }
00643 if ((B.r == F.r) &&
00644 (B.g == F.g) &&
00645 (B.b == F.b) &&
00646 (B.a == F.a)) {
00647 E1 = F;
00648 } else {
00649 E1 = E;
00650 }
00651 if ((D.r == H.r) &&
00652 (D.g == H.g) &&
00653 (D.b == H.b) &&
00654 (D.a == H.a)) {
00655 E2 = D;
00656 } else {
00657 E2 = E;
00658 }
00659 if ((H.r == F.r) &&
00660 (H.g == F.g) &&
00661 (H.b == F.b) &&
00662 (H.a == F.a)) {
00663 E3 = F;
00664 } else {
00665 E3 = E;
00666 }
00667 } else {
00668 E0 = E;
00669 E1 = E;
00670 E2 = E;
00671 E3 = E;
00672 }
00673 dst[dst_y + dst_x] = E0;
00674 dst_x++;
00675 dst[dst_y + dst_x] = E1;
00676 dst_x--;
00677 dst_y += width;
00678 dst[dst_y + dst_x] = E2;
00679 dst_x++;
00680 dst[dst_y + dst_x] = E3;
00681 dst_y -= width;
00682 dst_x++;
00683 }
00684
00685 dst_y += width;
00686 dst_y += width;
00687 src_y_idx += src_sprite->width;
00688 }
00689 }
00690
00691 void Blitter_32bppOptimized::FillRGBFromPalette(SpriteLoader::Sprite *sprite)
00692 {
00693 SpriteLoader::CommonPixel *spr = sprite->data;
00694
00695 for (uint y = 0; y < sprite->height; y++) {
00696 uint y_idx = y * sprite->width;
00697 for (uint x = 0; x < sprite->width; x++) {
00698 if (spr[y_idx + x].a == 0) {
00699 spr[y_idx + x].r = 0;
00700 spr[y_idx + x].g = 0;
00701 spr[y_idx + x].b = 0;
00702 spr[y_idx + x].m = 0;
00703 } else {
00704 if (spr[y_idx + x].m != 0) {
00705
00706 uint color = this->LookupColourInPalette(spr[y_idx + x].m);
00707 spr[y_idx + x].r = GB(color, 16, 8);
00708 spr[y_idx + x].g = GB(color, 8, 8);
00709 spr[y_idx + x].b = GB(color, 0, 8);
00710 }
00711 }
00712 }
00713 }
00714 }
00715
00716 byte *Blitter_32bppOptimized::FillRGBPalette(SpriteID id, byte *remap_data)
00717 {
00718 for (int idx = 0; (idx < MAX_PALETTE_TABLES); idx++) {
00719 if ((id == _rgb_palettes[idx].id) || (_rgb_palettes[idx].id == 0)) {
00720 _rgb_palettes[idx].id = id;
00721 for (int col_idx = 0; col_idx < 256; col_idx++) {
00722 _rgb_palettes[idx].tables[col_idx].data = this->LookupColourInPalette(remap_data[col_idx + 1]);
00723 }
00724 return (byte *)&(_rgb_palettes[idx].tables[0]);
00725 }
00726 }
00727 error("No more rgb palette tables available");
00728 return NULL;
00729 }
00730