| 1 | /* ScummVM - Scumm Interpreter |
| 2 | * Copyright (C) 2001 Ludvig Strigeus |
| 3 | * Copyright (C) 2001-2005 The ScummVM project |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License |
| 7 | * as published by the Free Software Foundation; either version 2 |
| 8 | * of the License, or (at your option) any later version. |
| 9 | |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 18 | * |
| 19 | * $Header: $ |
| 20 | * |
| 21 | */ |
| 22 | |
| 23 | #include "common/scaler.h" |
| 24 | #include "common/scaler/intern.h" |
| 25 | |
| 26 | // |
| 27 | // code taken from Pablo Medina (aka "pm") (pjmedina3@yahoo.com) |
| 28 | // you can find it here: http://2xpm.freeservers.com |
| 29 | // thanks for his great work |
| 30 | // implemented and fixed for ScummVM by Johannes Schickel (aka "LordHoto") (lordhoto [at] gmail [dot] com) |
| 31 | // |
| 32 | |
| 33 | template<int bitFormat> |
| 34 | static inline uint16 alphaBlendW128(uint16 A, uint16 B) { |
| 35 | return ((A & highBits) >> 1) + ((B & highBits) >> 1); |
| 36 | } |
| 37 | |
| 38 | template<int bitFormat> |
| 39 | static inline uint16 alphaBlendW64(uint16 A, uint16 B) { |
| 40 | return (redblueMask & ((redblueMask & A) + (((redblueMask & B) - (redblueMask & A)) >> 2))) | |
| 41 | (greenMask & ((greenMask & A) + (((greenMask & B) - (greenMask & A)) >> 2))); |
| 42 | } |
| 43 | |
| 44 | template<int bitFormat> |
| 45 | static inline uint16 alphaBlendW192(uint16 A, uint16 B) { |
| 46 | return (redblueMask & ((redblueMask & A) + ((((redblueMask & B) - (redblueMask & A)) * 192) >> 8))) | |
| 47 | (greenMask & ((greenMask & A) + ((((greenMask & B) - (greenMask & A)) * 192) >> 8))); |
| 48 | } |
| 49 | |
| 50 | template<int bitFormat> |
| 51 | void PM2x_intern(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { |
| 52 | uint32 nextLineSrc = srcPitch >> 1; |
| 53 | uint32 nextLine = dstPitch >> 1; |
| 54 | uint32 completeLineSrc = (srcPitch >> 1) - width; |
| 55 | uint32 completeLine = (dstPitch >> 1) - (2*width); |
| 56 | |
| 57 | const uint16 *startAddr2 = (const uint16*)srcPtr; |
| 58 | const uint16 *startAddr1 = startAddr2; |
| 59 | const uint16 *startAddr3 = startAddr2 + nextLineSrc; |
| 60 | |
| 61 | uint16 *dstPixel = (uint16*)dstPtr; |
| 62 | int y = height; |
| 63 | |
| 64 | uint16 E[4] = { 0, 0, 0, 0 }; |
| 65 | |
| 66 | while (y--) { |
| 67 | if (!y) |
| 68 | startAddr3 = startAddr2; |
| 69 | |
| 70 | byte pprev = 0; |
| 71 | int x = width; |
| 72 | |
| 73 | while (x--) { |
| 74 | uint16 PB = startAddr1[0]; |
| 75 | uint16 PE = startAddr2[0]; |
| 76 | uint16 PH = startAddr3[0]; |
| 77 | |
| 78 | uint16 PA = startAddr1[pprev]; |
| 79 | uint16 PD = startAddr2[pprev]; |
| 80 | uint16 PG = startAddr3[pprev]; |
| 81 | |
| 82 | uint16 PC = 0, PF = 0, PI_ = 0; |
| 83 | |
| 84 | if (x) { |
| 85 | PC = startAddr1[1]; |
| 86 | PF = startAddr2[1]; |
| 87 | PI_ = startAddr3[1]; |
| 88 | } else { |
| 89 | PC = startAddr1[0]; |
| 90 | PF = startAddr2[0]; |
| 91 | PI_ = startAddr3[0]; |
| 92 | } |
| 93 | |
| 94 | bool doNotReblit = false; |
| 95 | E[0] = E[1] = E[2] = E[3] = PE; |
| 96 | |
| 97 | if (!doNotReblit) { |
| 98 | if (PD != PF) { |
| 99 | if ((PE != PD) && (PD == PH) && (PD == PI_) && (PE != PG) |
| 100 | && ((PD != PG) || (PE != PF) || (PA != PD)) |
| 101 | && (!((PD == PA) && (PD == PG) && (PE == PB) && (PE == PF)))) { |
| 102 | E[2] = PH; |
| 103 | E[3] = alphaBlendW128<bitFormat>(E[3], PH); |
| 104 | doNotReblit = true; |
| 105 | } else if ((PE != PF) && (PF == PH) && (PF == PG) && (PE != PI_) |
| 106 | && ((PF != PI_) || (PE != PD) || (PC != PF)) |
| 107 | && (!((PF == PC) && (PF == PI_) && (PE == PB) && (PE == PD)))) { |
| 108 | E[2] = alphaBlendW128<bitFormat>(E[2], PH); |
| 109 | E[3] = PH; |
| 110 | doNotReblit = true; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | if (PB != PH) { |
| 115 | if (PE != PB) { |
| 116 | if ((PA != PB) || (PB != PC) || (PE != PH)) { |
| 117 | if ((PB == PD) && (PB == PG) && (PE != PA) |
| 118 | && (!((PD == PA) && (PD == PC) && (PE == PH) && (PE == PF)))) { |
| 119 | E[0] = alphaBlendW192<bitFormat>(E[0], PB); |
| 120 | E[2] = alphaBlendW64<bitFormat>(E[2], PB); |
| 121 | doNotReblit = true; |
| 122 | } else if ((PB == PF) && (PB == PI_) && (PE != PC) |
| 123 | && (!((PF == PC) && (PF == PA) && (PE == PH) && (PE == PD)))) { |
| 124 | E[1] = alphaBlendW128<bitFormat>(E[1], PB); |
| 125 | E[3] = alphaBlendW64<bitFormat>(E[3], PB); |
| 126 | doNotReblit = true; |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | if (PE != PH) { |
| 133 | if ((PG != PH) || (PE != PB) || (PH != PI)) { |
| 134 | if ((PH == PD) && (PH == PA) && (PE != PG) |
| 135 | && (!((PD == PG) && (PD == PI) && (PE == PB) && (PE == PF)))) { |
| 136 | E[2] = alphaBlendW192<bitFormat>(E[2], PH); |
| 137 | E[0] = alphaBlendW64<bitFormat>(E[0], PH); |
| 138 | doNotReblit = true; |
| 139 | } else if ((PH == PF) && (PH == PC) && (PE != PI) |
| 140 | && (!((PF == PI) && (PF == PG) && (PE == PB) && (PE == PD)))) { |
| 141 | E[3] = alphaBlendW192<bitFormat>(E[3], PH); |
| 142 | E[1] = alphaBlendW64<bitFormat>(E[1], PH); |
| 143 | doNotReblit = true; |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | if (!doNotReblit) { |
| 150 | if ((PB != PH) && (PD != PF)) |
| 151 | { |
| 152 | if ((PB == PD) && (PE != PD) |
| 153 | && (!((PE == PA) && (PB == PC) && (PE == PF))) // Block |
| 154 | && (!((PB == PA) && (PB == PG))) |
| 155 | && (!((PD == PA) && (PD == PC) && (PE == PF) && (PG != PD) && (PG != PE)))) |
| 156 | E[0] = alphaBlendW128<bitFormat>(E[0], PB); |
| 157 | |
| 158 | if ((PB == PF) && (PE != PF) |
| 159 | && (!((PE == PC) && (PB == PA) && (PE == PD))) // Block |
| 160 | && (!((PB == PC) && (PB == PI))) |
| 161 | && (!((PF == PA) && (PF == PC) && (PE == PD) && (PI != PF) && (PI != PE)))) |
| 162 | E[1] = alphaBlendW128<bitFormat>(E[1], PB); |
| 163 | |
| 164 | if ((PH == PD) && ((PE != PG) || (PE != PD)) |
| 165 | && (!((PE == PG) && (PH == PI) && (PE == PF))) // Block |
| 166 | && (!((PH == PG) && (PH == PA))) |
| 167 | && (!((PD == PG) && (PD == PI) && (PE == PF) && (PA != PD) && (PA != PE)))) |
| 168 | E[2] = alphaBlendW128<bitFormat>(E[2], PB); |
| 169 | |
| 170 | if ((PH == PF) && ((PE != PI) || (PE != PF)) |
| 171 | && (!((PE == PI) && (PH == PG) && (PE == PD))) // Block |
| 172 | && (!((PH == PI) && (PH == PC))) |
| 173 | && (!((PF == PG) && (PF == PI) && (PE == PD) && (PC != PF) && (PI != PE)))) |
| 174 | E[3] = alphaBlendW128<bitFormat>(E[3], PB); |
| 175 | |
| 176 | } |
| 177 | |
| 178 | if ((PD == PB) && (PD == PF) && (PD == PH) && (PD != PE)) { |
| 179 | if ((PD == PG) || (PD == PC)) { |
| 180 | E[1] = alphaBlendW128<bitFormat>(E[1], PD); |
| 181 | E[2] = E[1]; |
| 182 | } |
| 183 | |
| 184 | if ((PD == PA) || (PD == PI)) { |
| 185 | E[0] = alphaBlendW128<bitFormat>(E[0], PD); |
| 186 | E[3] = E[0]; |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | dstPixel[0] = E[0]; |
| 192 | dstPixel[1] = E[1]; |
| 193 | dstPixel[nextLine] = E[2]; |
| 194 | dstPixel[nextLine + 1] = E[3]; |
| 195 | |
| 196 | startAddr1++; |
| 197 | startAddr2++; |
| 198 | startAddr3++; |
| 199 | |
| 200 | dstPixel += 2; |
| 201 | pprev = 0; |
| 202 | } |
| 203 | |
| 204 | startAddr2 += completeLineSrc; |
| 205 | startAddr1 = startAddr2 - nextLineSrc; |
| 206 | startAddr3 = startAddr2 + nextLineSrc; |
| 207 | dstPixel += completeLine + nextLine; |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | void PM2x(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height) { |
| 212 | if (gBitFormat == 565) { |
| 213 | PM2x_intern<565>(srcPtr, srcPitch, dstPtr, dstPitch, width, height); |
| 214 | } else if (gBitFormat == 555) { |
| 215 | PM2x_intern<555>(srcPtr, srcPitch, dstPtr, dstPitch, width, height); |
| 216 | } |
| 217 | } |