# Ticket #8368: edge3x.cpp

File edge3x.cpp, 22.0 KB (added by , 19 years ago) |
---|

Line | |
---|---|

1 | /* ScummVM - Scumm Interpreter |

2 | * Copyright (C) 2001 Ludvig Strigeus |

3 | * Copyright (C) 2001-2004 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: /cvsroot/scummvm/scummvm/common/scaler/hq3x.h,v 1.2 2004/01/06 12:45:28 fingolfin Exp $ |

20 | * |

21 | */ |

22 | |

23 | /* Another edge-directed 3x anti-aliasing scaler for ScummVM |

24 | * |

25 | * Author: Eric A. Welsh |

26 | * |

27 | * Features: |

28 | * |

29 | * More anti-aliasing than advmame3x, but at the cost of some blurriness |

30 | * Low contrast areas are sharper than hq3x (which is very blurry) |

31 | * High contrast areas aren't as nice as hq3x (which is VERY nice) |

32 | * Overall, it strikes a good balance between sharpness and blurriness |

33 | * It could probably use some further speed optimization |

34 | * It's a bit slow... but ScummVM runs everything fine on my 1.53 Gz Athlon |

35 | */ |

36 | |

37 | #include "common/stdafx.h" |

38 | #include "common/scummsys.h" |

39 | #include "common/system.h" |

40 | |

41 | #define SIN45 0.7071067811865 /* sin of 45 degrees */ |

42 | #define LUMA_SHIFT 13 |

43 | |

44 | int32 luma_table[65536] = {0}; |

45 | int edge3x_init_flag = 0; |

46 | const uint16 *src_addr_min; /* start of src screen array */ |

47 | const uint16 *src_addr_max; /* end of src screen array */ |

48 | uint16 div3[189]; /* tables for pixel interpolation */ |

49 | uint16 div9[567]; |

50 | |

51 | /* faster than FPU atan(), nearly as accurate as single precision */ |

52 | double fast_atan(double v0) |

53 | { |

54 | double v2; |

55 | double v; |

56 | |

57 | v = fabs(v0); |

58 | v2 = v*v; |

59 | if (v > 1) |

60 | { |

61 | v2 = 1.570796326795 - |

62 | v * (0.446350590597 + v2) / |

63 | ((0.0900271979249 + v2) * (0.689454091687 + v2)); |

64 | if (v0 < 0) return -v2; |

65 | return v2; |

66 | } |

67 | v2 = v * (16.11094124024 + 7.191128136096 * v2) / |

68 | ((1.450422895714 + v2) * (11.10775435761 + v2)); |

69 | |

70 | if (v0 < 0) return -v2; |

71 | return v2; |

72 | } |

73 | |

74 | /* More complicated and slower than most algorithms, but it fails far less |

75 | * often (ie. assigning diagonal when it should be horizontal, or 90 degrees |

76 | * from what it should be). Slow, but necessary to avoid artifacts. |

77 | * |

78 | * Edge detection takes up a whopping 53% of the CPU time spent in ScummVM. |

79 | * Perhaps this could be optimized a bit more ... ? |

80 | */ |

81 | char convolve_edges_compass_luma(uint16 *pixels, int x_orig, int y_orig, |

82 | int w) |

83 | { |

84 | int32 *bptr; |

85 | uint16 *pptr; |

86 | int32 bplane[9]; |

87 | int32 sums_dir1, sums_dir2, sums_dir3, sums_dir4; /* NE E SE S */ |

88 | int32 max_sums; |

89 | int32 mag, mag1, mag2; |

90 | double angle; |

91 | double new_angle = 999; |

92 | int n; |

93 | |

94 | /* fill the 9 pixel window with luma values */ |

95 | bptr = bplane; |

96 | pptr = pixels; |

97 | for (n = 0; n < 9; n++) |

98 | *bptr++ = luma_table[*pptr++]; |

99 | bptr = bplane; |

100 | |

101 | /* bi-directional edge detection */ |

102 | /* mis-detections are easier to correct than the vector-based method */ |

103 | mag = (bptr[2] + bptr[4] + bptr[6]) << 1; |

104 | mag1 = labs((3 * (bptr[1] + bptr[3]) - mag) >> 1); |

105 | mag2 = labs((3 * (bptr[5] + bptr[7]) - mag) >> 1); |

106 | mag = mag1; |

107 | if (mag2 > mag) mag = mag2; |

108 | sums_dir1 = mag; |

109 | |

110 | mag = bptr[3] + bptr[4] + bptr[5]; |

111 | mag1 = labs(bptr[0] + bptr[1] + bptr[2] - mag); |

112 | mag2 = labs(bptr[6] + bptr[7] + bptr[8] - mag); |

113 | mag = mag1; |

114 | if (mag2 > mag) mag = mag2; |

115 | sums_dir2 = mag; |

116 | |

117 | mag = (bptr[0] + bptr[4] + bptr[8]) << 1; |

118 | mag1 = labs((3 * (bptr[1] + bptr[5]) - mag) >> 1); |

119 | mag2 = labs((3 * (bptr[3] + bptr[7]) - mag) >> 1); |

120 | mag = mag1; |

121 | if (mag2 > mag) mag = mag2; |

122 | sums_dir3 = mag; |

123 | |

124 | mag = bptr[1] + bptr[4] + bptr[7]; |

125 | mag1 = labs(bptr[0] + bptr[3] + bptr[6] - mag); |

126 | mag2 = labs(bptr[2] + bptr[5] + bptr[8] - mag); |

127 | mag = mag1; |

128 | if (mag2 > mag) mag = mag2; |

129 | sums_dir4 = mag; |

130 | |

131 | /* find the strongest edge */ |

132 | max_sums = sums_dir1; |

133 | if (sums_dir2 > max_sums) max_sums = sums_dir2; |

134 | if (sums_dir3 > max_sums) max_sums = sums_dir3; |

135 | if (sums_dir4 > max_sums) max_sums = sums_dir4; |

136 | |

137 | n = 0; |

138 | if (max_sums == sums_dir1) |

139 | { |

140 | new_angle = 135; |

141 | n++; |

142 | } |

143 | if (max_sums == sums_dir2) |

144 | { |

145 | new_angle = 0; |

146 | n++; |

147 | } |

148 | if (max_sums == sums_dir3) |

149 | { |

150 | new_angle = 45; |

151 | n++; |

152 | } |

153 | if (max_sums == sums_dir4) |

154 | { |

155 | new_angle = 90; |

156 | n++; |

157 | } |

158 | |

159 | if (max_sums == 0) /* grid of solid color */ |

160 | return 0; |

161 | if (max_sums && n == 1) /* we found a strong edge */ |

162 | { |

163 | angle = new_angle; |

164 | } |

165 | else if (n == 4) /* x, +, . type patterns */ |

166 | { |

167 | return '*'; |

168 | } |

169 | else /* difficult edge, try vector method */ |

170 | { |

171 | double x, y; |

172 | |

173 | sums_dir1 = (3 * (bptr[1] - bptr[3] + bptr[5] - bptr[7])) >> 1; |

174 | |

175 | sums_dir2 = bptr[0] + bptr[1] + bptr[2] - |

176 | bptr[6] - bptr[7] - bptr[8]; |

177 | |

178 | sums_dir3 = (3 * (bptr[1] + bptr[3] - bptr[5] - bptr[7])) >> 1; |

179 | |

180 | sums_dir4 = bptr[0] - bptr[2] + bptr[3] - |

181 | bptr[5] + bptr[6] - bptr[8]; |

182 | |

183 | /* add the vectors in x,y space, North points up */ /* NE E SE S */ |

184 | x = sums_dir1 * SIN45; |

185 | x += sums_dir2; |

186 | x += sums_dir3 * SIN45; |

187 | y = sums_dir1 * SIN45; |

188 | y -= sums_dir3 * SIN45; |

189 | y -= sums_dir4; |

190 | |

191 | if (x) |

192 | { |

193 | angle = 57.29577951307 * fast_atan(y / x); |

194 | if (x < 0) angle += 180; |

195 | } |

196 | else |

197 | { |

198 | if (y > 0) angle = 90; |

199 | else if (y < 0) angle = -90; |

200 | else return '*'; |

201 | } |

202 | } |

203 | |

204 | /* fix detection errors that are off by 90 degrees */ |

205 | { |

206 | int32 dist1, dist2; |

207 | int32 dist_good, dist_bad; |

208 | |

209 | if (angle < 0) angle += 360; |

210 | |

211 | /* horizontal */ |

212 | if ((angle > (180 - 22.5) && angle < (180 + 22.5)) || |

213 | angle < 22.5 || angle > (360 - 22.5)) |

214 | { |

215 | dist1 = bptr[4] - bptr[3]; |

216 | dist2 = bptr[4] - bptr[5]; |

217 | dist_good = dist1*dist1 + dist2*dist2; |

218 | |

219 | dist1 = bptr[4] - bptr[1]; |

220 | dist2 = bptr[4] - bptr[7]; |

221 | dist_bad = dist1*dist1 + dist2*dist2; |

222 | |

223 | if (dist_good <= dist_bad) |

224 | return '-'; |

225 | |

226 | return '|'; |

227 | } |

228 | |

229 | /* vertical */ |

230 | if ((angle > (90 - 22.5) && angle < (90 + 22.5)) || |

231 | (angle > (90 - 22.5 + 180) && angle < (90 + 22.5 + 180))) |

232 | { |

233 | dist1 = bptr[4] - bptr[1]; |

234 | dist2 = bptr[4] - bptr[7]; |

235 | dist_good = dist1*dist1 + dist2*dist2; |

236 | |

237 | dist1 = bptr[4] - bptr[3]; |

238 | dist2 = bptr[4] - bptr[5]; |

239 | dist_bad = dist1*dist1 + dist2*dist2; |

240 | |

241 | if (dist_good <= dist_bad) |

242 | return '|'; |

243 | |

244 | return '-'; |

245 | } |

246 | |

247 | /* 45 */ |

248 | if ((angle > (45 - 22.5) && angle < (45 + 22.5)) || |

249 | (angle > (45 - 22.5 + 180) && angle < (45 + 22.5 + 180))) |

250 | { |

251 | dist1 = bptr[4] - bptr[0]; |

252 | dist2 = bptr[4] - bptr[8]; |

253 | dist_good = dist1*dist1 + dist2*dist2; |

254 | |

255 | /* side diags */ |

256 | dist1 = bptr[1] - bptr[5]; |

257 | dist2 = bptr[3] - bptr[7]; |

258 | dist_good += dist1*dist1 + dist2*dist2; |

259 | |

260 | dist1 = bptr[4] - bptr[2]; |

261 | dist2 = bptr[4] - bptr[6]; |

262 | dist_bad = dist1*dist1 + dist2*dist2; |

263 | |

264 | /* side diags */ |

265 | dist1 = bptr[1] - bptr[3]; |

266 | dist2 = bptr[5] - bptr[7]; |

267 | dist_bad += dist1*dist1 + dist2*dist2; |

268 | |

269 | if (dist_good <= dist_bad) |

270 | return '\\'; |

271 | |

272 | return '/'; |

273 | } |

274 | |

275 | /* 135 */ |

276 | if ((angle > (135 - 22.5) && angle < (135 + 22.5)) || |

277 | (angle > (135 - 22.5 + 180) && angle < (135 + 22.5 + 180))) |

278 | { |

279 | dist1 = bptr[4] - bptr[2]; |

280 | dist2 = bptr[4] - bptr[6]; |

281 | dist_good = dist1*dist1 + dist2*dist2; |

282 | |

283 | /* side diags */ |

284 | dist1 = bptr[1] - bptr[3]; |

285 | dist2 = bptr[5] - bptr[7]; |

286 | dist_good += dist1*dist1 + dist2*dist2; |

287 | |

288 | dist1 = bptr[4] - bptr[0]; |

289 | dist2 = bptr[4] - bptr[8]; |

290 | dist_bad = dist1*dist1 + dist2*dist2; |

291 | |

292 | /* side diags */ |

293 | dist1 = bptr[1] - bptr[5]; |

294 | dist2 = bptr[3] - bptr[7]; |

295 | dist_bad += dist1*dist1 + dist2*dist2; |

296 | |

297 | if (dist_good <= dist_bad) |

298 | return '/'; |

299 | |

300 | return '\\'; |

301 | } |

302 | } |

303 | |

304 | return '*'; |

305 | } |

306 | |

307 | /* From ScummVM hq2x/hq3x scalers (Maxim Stepin and Max Horn) */ |

308 | #define highBits 0xF7DEF7DE |

309 | #define lowBits 0x08210821 |

310 | #define qhighBits 0xE79CE79C |

311 | #define qlowBits 0x18631863 |

312 | #define redblueMask 0xF81F |

313 | #define greenMask 0x07E0 |

314 | |

315 | /* From ScummVM hq2x/hq3x scalers (Maxim Stepin and Max Horn) */ |

316 | /** |

317 | * Interpolate two 16 bit pixel pairs at once with equal weights 1. |

318 | * In particular, A and B can contain two pixels/each in the upper |

319 | * and lower halves. |

320 | */ |

321 | uint32 INTERPOLATE(uint32 A, uint32 B) |

322 | { |

323 | return (((A & highBits) >> 1) + ((B & highBits) >> 1) + (A & B & lowBits)); |

324 | } |

325 | |

326 | /* From ScummVM hq2x/hq3x scalers (Maxim Stepin and Max Horn) */ |

327 | /** |

328 | * Interpolate four 16 bit pixel pairs at once with equal weights 1. |

329 | * In particular, A and B can contain two pixels/each in the upper |

330 | * and lower halves. |

331 | */ |

332 | uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D) |

333 | { |

334 | uint32 x = ((A & qhighBits) >> 2) + ((B & qhighBits) >> 2) + ((C & qhighBits) >> 2) + ((D & qhighBits) >> 2); |

335 | uint32 y = ((A & qlowBits) + (B & qlowBits) + (C & qlowBits) + (D & qlowBits)) >> 2; |

336 | |

337 | y &= qlowBits; |

338 | return x + y; |

339 | } |

340 | |

341 | uint16 average_three_pixels(uint16 pixel1, uint16 pixel2, uint16 pixel3) |

342 | { |

343 | uint32 rsum, gsum, bsum; |

344 | |

345 | rsum = (pixel1 & 0xF800); |

346 | rsum += (pixel2 & 0xF800); |

347 | rsum += (pixel3 & 0xF800); |

348 | rsum = div3[rsum >> 11]; |

349 | |

350 | gsum = (pixel1 & 0x07E0); |

351 | gsum += (pixel2 & 0x07E0); |

352 | gsum += (pixel3 & 0x07E0); |

353 | gsum = div3[gsum >> 5]; |

354 | |

355 | bsum = (pixel1 & 0x001F); |

356 | bsum += (pixel2 & 0x001F); |

357 | bsum += (pixel3 & 0x001F); |

358 | bsum = div3[bsum]; |

359 | |

360 | return ((rsum << 11) | (gsum << 5) | bsum); |

361 | } |

362 | |

363 | uint16 average_one_third(uint16 pixel1, uint16 pixel2) |

364 | { |

365 | uint32 rsum, gsum, bsum; |

366 | |

367 | rsum = (pixel1 & 0xF800) << 1; |

368 | rsum += (pixel2 & 0xF800); |

369 | rsum = div3[rsum >> 11]; |

370 | |

371 | gsum = (pixel1 & 0x07E0) << 1; |

372 | gsum += (pixel2 & 0x07E0); |

373 | gsum = div3[gsum >> 5]; |

374 | |

375 | bsum = (pixel1 & 0x001F) << 1; |

376 | bsum += (pixel2 & 0x001F); |

377 | bsum = div3[bsum]; |

378 | |

379 | return ((rsum << 11) | (gsum << 5) | bsum); |

380 | } |

381 | |

382 | /* interpolate a diagnoal pixel for linear interpolation on a 3x3 grid */ |

383 | uint16 average_four_pixels_radial(uint16 pixel1, uint16 pixel2, |

384 | uint16 pixel3, uint16 pixel4) |

385 | { |

386 | uint32 rsum, gsum, bsum; |

387 | |

388 | rsum = (pixel1 & 0xF800) << 2; |

389 | rsum += (pixel2 & 0xF800) << 1; |

390 | rsum += (pixel3 & 0xF800) << 1; |

391 | rsum += (pixel4 & 0xF800); |

392 | rsum = div9[rsum >> 11]; |

393 | |

394 | gsum = (pixel1 & 0x07E0) << 2; |

395 | gsum += (pixel2 & 0x07E0) << 1; |

396 | gsum += (pixel3 & 0x07E0) << 1; |

397 | gsum += (pixel4 & 0x07E0); |

398 | gsum = div9[gsum >> 5]; |

399 | |

400 | bsum = (pixel1 & 0x001F) << 2; |

401 | bsum += (pixel2 & 0x001F) << 1; |

402 | bsum += (pixel3 & 0x001F) << 1; |

403 | bsum += (pixel4 & 0x001F); |

404 | bsum = div9[bsum]; |

405 | |

406 | return ((rsum << 11) | (gsum << 5) | bsum); |

407 | } |

408 | |

409 | /* perform different interpolations depending on the detected edge */ |

410 | void anti_alias_grid(uint8 *dptr, int dstPitch, |

411 | uint16 *pixels, char edge_type) |

412 | { |

413 | uint16 *dptr2; |

414 | uint16 tmp_pixel; |

415 | uint16 center = pixels[4]; |

416 | static uint16 tmp[9]; |

417 | uint16 *ptmp; |

418 | |

419 | switch (edge_type) |

420 | { |

421 | case 0: |

422 | dptr2 = ((uint16 *) (dptr - dstPitch)) - 1; |

423 | *dptr2++ = center; |

424 | *dptr2++ = center; |

425 | *dptr2 = center; |

426 | dptr2 = ((uint16 *) dptr) - 1; |

427 | *dptr2++ = center; |

428 | *dptr2++ = center; |

429 | *dptr2 = center; |

430 | dptr2 = ((uint16 *) (dptr + dstPitch)) - 1; |

431 | *dptr2++ = center; |

432 | *dptr2++ = center; |

433 | *dptr2 = center; |

434 | |

435 | return; |

436 | |

437 | break; |

438 | |

439 | case '-': |

440 | tmp[0] = tmp[3] = tmp[6] = average_one_third(center, pixels[3]); |

441 | tmp[1] = tmp[4] = tmp[7] = center; |

442 | tmp[2] = tmp[5] = tmp[8] = average_one_third(center, pixels[5]); |

443 | |

444 | if (center == pixels[0]) tmp[0] = center; |

445 | if (center == pixels[2]) tmp[2] = center; |

446 | if (center == pixels[6]) tmp[6] = center; |

447 | if (center == pixels[8]) tmp[8] = center; |

448 | |

449 | if (center == pixels[0] || center == pixels[6]) |

450 | tmp[3] = INTERPOLATE(tmp[0], tmp[6]); |

451 | if (center == pixels[2] || center == pixels[8]) |

452 | tmp[5] = INTERPOLATE(tmp[2], tmp[8]); |

453 | |

454 | break; |

455 | |

456 | case '|': |

457 | tmp[0] = tmp[1] = tmp[2] = average_one_third(center, pixels[1]); |

458 | tmp[3] = tmp[4] = tmp[5] = center; |

459 | tmp[6] = tmp[7] = tmp[8] = average_one_third(center, pixels[7]); |

460 | |

461 | if (center == pixels[0]) tmp[0] = center; |

462 | if (center == pixels[2]) tmp[2] = center; |

463 | if (center == pixels[6]) tmp[6] = center; |

464 | if (center == pixels[8]) tmp[8] = center; |

465 | |

466 | if (center == pixels[0] || center == pixels[2]) |

467 | tmp[1] = INTERPOLATE(tmp[0], tmp[2]); |

468 | if (center == pixels[6] || center == pixels[8]) |

469 | tmp[7] = INTERPOLATE(tmp[6], tmp[8]); |

470 | |

471 | break; |

472 | |

473 | case '/': |

474 | if (pixels[1] == center && center == pixels[6]) |

475 | tmp[0] = Q_INTERPOLATE(pixels[1], pixels[3], |

476 | center, pixels[6]); |

477 | else if (pixels[2] == pixels[3] && pixels[3] == center) |

478 | tmp[0] = Q_INTERPOLATE(pixels[1], pixels[2], |

479 | pixels[3], center); |

480 | else |

481 | tmp[0] = average_three_pixels(pixels[1], pixels[3], center); |

482 | |

483 | tmp[2] = average_one_third(center, pixels[2]); |

484 | |

485 | if (pixels[1] == center) |

486 | tmp[1] = center; |

487 | else |

488 | { |

489 | tmp_pixel = average_one_third(pixels[1], center); |

490 | tmp[1] = Q_INTERPOLATE(tmp_pixel, center, |

491 | tmp[0], |

492 | tmp[2]); |

493 | } |

494 | |

495 | tmp[6] = average_one_third(center, pixels[6]); |

496 | if (pixels[2] == center && center == pixels[7]) |

497 | tmp[8] = Q_INTERPOLATE(pixels[2], center, |

498 | pixels[5], pixels[7]); |

499 | else if (center == pixels[5] && pixels[5] == pixels[6]) |

500 | tmp[8] = Q_INTERPOLATE(center, pixels[5], |

501 | pixels[6], pixels[7]); |

502 | else |

503 | tmp[8] = average_three_pixels(center, pixels[5], pixels[7]); |

504 | |

505 | if (pixels[7] == center) |

506 | tmp[7] = center; |

507 | else |

508 | { |

509 | tmp_pixel = average_one_third(pixels[7], center); |

510 | tmp[7] = Q_INTERPOLATE(tmp_pixel, center, |

511 | tmp[6], |

512 | tmp[8]); |

513 | } |

514 | |

515 | if (pixels[3] == center) |

516 | tmp[3] = center; |

517 | else |

518 | { |

519 | tmp_pixel = average_one_third(pixels[3], center); |

520 | tmp[3] = Q_INTERPOLATE(tmp_pixel, center, |

521 | tmp[0], |

522 | tmp[6]); |

523 | } |

524 | |

525 | tmp[4] = center; |

526 | |

527 | if (pixels[5] == center) |

528 | tmp[5] = center; |

529 | else |

530 | { |

531 | tmp_pixel = average_one_third(pixels[5], center); |

532 | tmp[5] = Q_INTERPOLATE(tmp_pixel, center, |

533 | tmp[2], |

534 | tmp[8]); |

535 | } |

536 | |

537 | break; |

538 | |

539 | case '\\': |

540 | tmp[0] = average_one_third(center, pixels[0]); |

541 | |

542 | if (pixels[1] == center && center == pixels[8]) |

543 | tmp[2] = Q_INTERPOLATE(pixels[1], center, |

544 | pixels[5], pixels[8]); |

545 | else if (pixels[0] == center && center == pixels[5]) |

546 | tmp[2] = Q_INTERPOLATE(pixels[0], pixels[1], |

547 | center, pixels[5]); |

548 | else |

549 | tmp[2] = average_three_pixels(pixels[1], center, pixels[5]); |

550 | |

551 | if (pixels[1] == center) |

552 | tmp[1] = center; |

553 | else |

554 | { |

555 | tmp_pixel = average_one_third(pixels[1], center); |

556 | tmp[1] = Q_INTERPOLATE(tmp_pixel, center, |

557 | tmp[0], |

558 | tmp[2]); |

559 | } |

560 | |

561 | if (pixels[0] == center && center == pixels[7]) |

562 | tmp[6] = Q_INTERPOLATE(pixels[0], pixels[3], |

563 | center, pixels[7]); |

564 | else if (pixels[3] == center && center == pixels[8]) |

565 | tmp[6] = Q_INTERPOLATE(pixels[3], center, |

566 | pixels[7], pixels[8]); |

567 | else |

568 | tmp[6] = average_three_pixels(pixels[3], center, pixels[7]); |

569 | |

570 | tmp[8] = average_one_third(center, pixels[8]); |

571 | |

572 | if (pixels[7] == center) |

573 | tmp[7] = center; |

574 | else |

575 | { |

576 | tmp_pixel = average_one_third(pixels[7], center); |

577 | tmp[7] = Q_INTERPOLATE(tmp_pixel, center, |

578 | tmp[6], |

579 | tmp[8]); |

580 | } |

581 | |

582 | if (pixels[3] == center) |

583 | tmp[3] = center; |

584 | else |

585 | { |

586 | tmp_pixel = average_one_third(pixels[3], center); |

587 | tmp[3] = Q_INTERPOLATE(tmp_pixel, center, |

588 | tmp[0], |

589 | tmp[6]); |

590 | } |

591 | |

592 | tmp[4] = center; |

593 | |

594 | if (pixels[5] == center) |

595 | tmp[5] = center; |

596 | else |

597 | { |

598 | tmp_pixel = average_one_third(pixels[5], center); |

599 | tmp[5] = Q_INTERPOLATE(tmp_pixel, center, |

600 | tmp[2], |

601 | tmp[8]); |

602 | } |

603 | |

604 | break; |

605 | |

606 | case '*': |

607 | tmp[0] = average_four_pixels_radial(center, pixels[1], |

608 | pixels[3], pixels[0]); |

609 | tmp[1] = average_one_third(center, pixels[1]); |

610 | tmp[2] = average_four_pixels_radial(center, pixels[1], |

611 | pixels[5], pixels[2]); |

612 | tmp[3] = average_one_third(center, pixels[3]); |

613 | tmp[4] = center; |

614 | tmp[5] = average_one_third(center, pixels[5]); |

615 | tmp[6] = average_four_pixels_radial(center, pixels[3], |

616 | pixels[7], pixels[6]); |

617 | tmp[7] = average_one_third(center, pixels[7]); |

618 | tmp[8] = average_four_pixels_radial(center, pixels[5], |

619 | pixels[7], pixels[8]); |

620 | |

621 | |

622 | if (center == pixels[1]) |

623 | tmp[0] = tmp[2] = center; |

624 | if (center == pixels[3]) |

625 | tmp[0] = tmp[6] = center; |

626 | if (center == pixels[5]) |

627 | tmp[2] = tmp[8] = center; |

628 | if (center == pixels[7]) |

629 | tmp[6] = tmp[8] = center; |

630 | |

631 | if (center == pixels[0]) |

632 | tmp[0] = center; |

633 | if (center == pixels[2]) |

634 | tmp[2] = center; |

635 | if (center == pixels[6]) |

636 | tmp[6] = center; |

637 | if (center == pixels[8]) |

638 | tmp[8] = center; |

639 | |

640 | break; |

641 | |

642 | default: |

643 | return; |

644 | |

645 | break; |

646 | } |

647 | |

648 | ptmp = tmp; |

649 | dptr2 = ((uint16 *) (dptr - dstPitch)) - 1; |

650 | *dptr2++ = *ptmp++; |

651 | *dptr2++ = *ptmp++; |

652 | *dptr2 = *ptmp++; |

653 | dptr2 = ((uint16 *) dptr) - 1; |

654 | *dptr2++ = *ptmp++; |

655 | *dptr2++ = *ptmp++; |

656 | *dptr2 = *ptmp++; |

657 | dptr2 = ((uint16 *) (dptr + dstPitch)) - 1; |

658 | *dptr2++ = *ptmp++; |

659 | *dptr2++ = *ptmp++; |

660 | *dptr2 = *ptmp; |

661 | } |

662 | |

663 | /* perform edge detection, then interpolate */ |

664 | void anti_alias_pass(const uint8 *src, uint8 *dst, |

665 | int w, int h, int w_new, int h_new, |

666 | int srcPitch, int dstPitch) |

667 | { |

668 | int x, y; |

669 | const uint16 *sptr16; |

670 | uint16 *dptr16; |

671 | |

672 | for (y = 0; y < h; y++) |

673 | { |

674 | sptr16 = ((const uint16 *) (src + y * srcPitch)) + 0; |

675 | dptr16 = ((uint16 *) (dst + y * dstPitch * 3 + dstPitch)) + 1 + 0; |

676 | for (x = 0; x < w; x++, sptr16++, dptr16 += 3) |

677 | { |

678 | const uint16 *sptr2, *addr3; |

679 | static uint16 pixels[9]; |

680 | uint16 *pptr = pixels; |

681 | char edge_type; |

682 | |

683 | sptr2 = ((const uint16 *) ((const uint8 *) sptr16 - srcPitch)) - 1; |

684 | addr3 = ((const uint16 *) ((const uint8 *) sptr16 + srcPitch)) + 1; |

685 | |

686 | /* fill the 3x3 grid */ |

687 | if (sptr2 >= src_addr_min && addr3 <= src_addr_max) |

688 | { |

689 | memcpy(pixels, sptr2, 3*sizeof(uint16)); |

690 | memcpy(pixels+3, sptr16 - 1, 3*sizeof(uint16)); |

691 | memcpy(pixels+6, addr3 - 2, 3*sizeof(uint16)); |

692 | } |

693 | else /* if we go off the screen, set the pixel to 0 */ |

694 | { |

695 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

696 | *pptr++ = *sptr2++; |

697 | else { |

698 | *pptr++ = 0; |

699 | sptr2++; |

700 | } |

701 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

702 | *pptr++ = *sptr2++; |

703 | else { |

704 | *pptr++ = 0; |

705 | sptr2++; |

706 | } |

707 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

708 | *pptr++ = *sptr2; |

709 | else |

710 | *pptr++ = 0; |

711 | |

712 | sptr2 = sptr16 - 1; |

713 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

714 | *pptr++ = *sptr2++; |

715 | else { |

716 | *pptr++ = 0; |

717 | sptr2++; |

718 | } |

719 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

720 | *pptr++ = *sptr2++; |

721 | else { |

722 | *pptr++ = 0; |

723 | sptr2++; |

724 | } |

725 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

726 | *pptr++ = *sptr2; |

727 | else |

728 | *pptr++ = 0; |

729 | |

730 | sptr2 = addr3 - 2; |

731 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

732 | *pptr++ = *sptr2++; |

733 | else { |

734 | *pptr++ = 0; |

735 | sptr2++; |

736 | } |

737 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

738 | *pptr++ = *sptr2++; |

739 | else { |

740 | *pptr++ = 0; |

741 | sptr2++; |

742 | } |

743 | if (sptr2 >= src_addr_min && sptr2 <= src_addr_max) |

744 | *pptr = *sptr2; |

745 | else |

746 | *pptr = 0; |

747 | } |

748 | |

749 | edge_type = convolve_edges_compass_luma(pixels, x, y, w); |

750 | anti_alias_grid((uint8 *) dptr16, dstPitch, pixels, edge_type); |

751 | } |

752 | } |

753 | } |

754 | |

755 | void initialize_tables(const uint8 *srcPtr, uint32 srcPitch, |

756 | uint8 *dstPtr, uint32 dstPitch, |

757 | int width, int height) |

758 | { |

759 | double r_float, g_float, b_float, luma; |

760 | int r, g, b; |

761 | |

762 | /* initialize luma table */ |

763 | for (r = 0; r < 32; r++) |

764 | { |

765 | r_float = r / 31.0; |

766 | |

767 | for (g = 0; g < 64; g++) |

768 | { |

769 | g_float = g / 63.0; |

770 | |

771 | for (b = 0; b < 32; b++) |

772 | { |

773 | b_float = b / 31.0; |

774 | |

775 | luma = 0.299*r_float + 0.587*g_float + 0.114*b_float; |

776 | luma_table[(r << 11) | (g << 5) | b] = |

777 | (int32)(luma * (1 << LUMA_SHIFT) + 0.5); |

778 | } |

779 | } |

780 | } |

781 | |

782 | /* initialize interpolation division tables */ |

783 | for (r = 0; r <= 189; r++) |

784 | div3[r] = ((r<<1)+1) / 6; |

785 | for (r = 0; r <= 567; r++) |

786 | div9[r] = ((r<<1)+1) / 18; |

787 | |

788 | /* set initial best guess on min/max screen addresses */ |

789 | src_addr_min = (const uint16 *) srcPtr; |

790 | src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) + |

791 | (width - 1); |

792 | } |

793 | |

794 | void Edge3x(const uint8 *srcPtr, uint32 srcPitch, |

795 | uint8 *dstPtr, uint32 dstPitch, int width, int height) |

796 | { |

797 | if (!edge3x_init_flag) |

798 | { |

799 | initialize_tables(srcPtr, srcPitch, dstPtr, dstPitch, width, height); |

800 | edge3x_init_flag = 1; |

801 | } |

802 | |

803 | if (width == g_system->getWidth() && |

804 | height == g_system->getHeight()) |

805 | { |

806 | src_addr_min = (const uint16 *) srcPtr; |

807 | src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) + |

808 | (width - 1); |

809 | } |

810 | |

811 | anti_alias_pass(srcPtr, dstPtr, width, height, |

812 | 3*width, 3*height, srcPitch, dstPitch); |

813 | } |