1 | /*****************************************************************************\ |
2 | Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. |
3 | This file is licensed under the Snes9x License. |
4 | For further information, consult the LICENSE file in the root directory. |
5 | \*****************************************************************************/ |
6 | |
7 | #include "snes9x.h" |
8 | #include "blit.h" |
9 | |
10 | #define ALL_COLOR_MASK (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) |
11 | |
12 | #define lowPixelMask (RGB_LOW_BITS_MASK) |
13 | #define qlowPixelMask ((RGB_HI_BITS_MASK >> 3) | TWO_LOW_BITS_MASK) |
14 | #define highBitsMask (ALL_COLOR_MASK & RGB_REMOVE_LOW_BITS_MASK) |
15 | #define colorMask (((~RGB_HI_BITS_MASK & ALL_COLOR_MASK) << 16) | (~RGB_HI_BITS_MASK & ALL_COLOR_MASK)) |
16 | |
17 | static snes_ntsc_t *ntsc = NULL; |
18 | static uint8 *XDelta = NULL; |
19 | |
20 | |
21 | bool8 S9xBlitFilterInit (void) |
22 | { |
23 | XDelta = new uint8[SNES_WIDTH * SNES_HEIGHT_EXTENDED * 4]; |
24 | if (!XDelta) |
25 | return (FALSE); |
26 | |
27 | S9xBlitClearDelta(); |
28 | |
29 | return (TRUE); |
30 | } |
31 | |
32 | void S9xBlitFilterDeinit (void) |
33 | { |
34 | if (XDelta) |
35 | { |
36 | delete[] XDelta; |
37 | XDelta = NULL; |
38 | } |
39 | } |
40 | |
41 | void S9xBlitClearDelta (void) |
42 | { |
43 | uint32 *d = (uint32 *) XDelta; |
44 | |
45 | for (int y = 0; y < SNES_HEIGHT_EXTENDED; y++) |
46 | for (int x = 0; x < SNES_WIDTH; x++) |
47 | *d++ = 0x80008000; |
48 | } |
49 | |
50 | bool8 S9xBlitNTSCFilterInit (void) |
51 | { |
52 | ntsc = (snes_ntsc_t *) malloc(sizeof(snes_ntsc_t)); |
53 | if (!ntsc) |
54 | return (FALSE); |
55 | |
56 | snes_ntsc_init(ntsc, &snes_ntsc_composite); |
57 | return (TRUE); |
58 | } |
59 | |
60 | void S9xBlitNTSCFilterDeinit (void) |
61 | { |
62 | if (ntsc) |
63 | { |
64 | free(ntsc); |
65 | ntsc = NULL; |
66 | } |
67 | } |
68 | |
69 | void S9xBlitNTSCFilterSet (const snes_ntsc_setup_t *setup) |
70 | { |
71 | snes_ntsc_init(ntsc, setup); |
72 | } |
73 | |
74 | void S9xBlitPixSimple1x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
75 | { |
76 | width <<= 1; |
77 | |
78 | for (; height; height--) |
79 | { |
80 | memcpy(dstPtr, srcPtr, width); |
81 | srcPtr += srcRowBytes; |
82 | dstPtr += dstRowBytes; |
83 | } |
84 | } |
85 | |
86 | void S9xBlitPixSimple1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
87 | { |
88 | width <<= 1; |
89 | |
90 | for (; height; height--) |
91 | { |
92 | memcpy(dstPtr, srcPtr, width); |
93 | dstPtr += dstRowBytes; |
94 | memcpy(dstPtr, srcPtr, width); |
95 | srcPtr += srcRowBytes; |
96 | dstPtr += dstRowBytes; |
97 | } |
98 | } |
99 | |
100 | void S9xBlitPixSimple2x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
101 | { |
102 | for (; height; height--) |
103 | { |
104 | uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr; |
105 | |
106 | for (int i = 0; i < (width >> 1); i++) |
107 | { |
108 | *dP++ = *bP; |
109 | *dP++ = *bP++; |
110 | |
111 | *dP++ = *bP; |
112 | *dP++ = *bP++; |
113 | } |
114 | |
115 | srcPtr += srcRowBytes; |
116 | dstPtr += dstRowBytes; |
117 | } |
118 | } |
119 | |
120 | void S9xBlitPixSimple2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
121 | { |
122 | uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta; |
123 | dstRowBytes <<= 1; |
124 | |
125 | for (; height; height--) |
126 | { |
127 | uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr; |
128 | uint32 currentPixel, lastPixel, currentPixA, currentPixB, colorA, colorB; |
129 | |
130 | for (int i = 0; i < (width >> 1); i++) |
131 | { |
132 | currentPixel = *bP; |
133 | lastPixel = *xP; |
134 | |
135 | if (currentPixel != lastPixel) |
136 | { |
137 | #ifdef MSB_FIRST |
138 | colorA = (currentPixel >> 16) & 0xFFFF; |
139 | colorB = (currentPixel ) & 0xFFFF; |
140 | #else |
141 | colorA = (currentPixel ) & 0xFFFF; |
142 | colorB = (currentPixel >> 16) & 0xFFFF; |
143 | #endif |
144 | |
145 | currentPixA = (colorA << 16) | colorA; |
146 | currentPixB = (colorB << 16) | colorB; |
147 | |
148 | dP1[0] = currentPixA; |
149 | dP1[1] = currentPixB; |
150 | dP2[0] = currentPixA; |
151 | dP2[1] = currentPixB; |
152 | |
153 | *xP = *bP; |
154 | } |
155 | |
156 | bP++; |
157 | xP++; |
158 | dP1 += 2; |
159 | dP2 += 2; |
160 | } |
161 | |
162 | srcPtr += srcRowBytes; |
163 | deltaPtr += srcRowBytes; |
164 | dstPtr += dstRowBytes; |
165 | dstPtr2 += dstRowBytes; |
166 | } |
167 | } |
168 | |
169 | void S9xBlitPixBlend1x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
170 | { |
171 | for (; height; height--) |
172 | { |
173 | uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr; |
174 | uint16 prev, curr; |
175 | |
176 | prev = *bP; |
177 | |
178 | for (int i = 0; i < (width >> 1); i++) |
179 | { |
180 | curr = *bP++; |
181 | *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); |
182 | prev = curr; |
183 | |
184 | curr = *bP++; |
185 | *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); |
186 | prev = curr; |
187 | } |
188 | |
189 | srcPtr += srcRowBytes; |
190 | dstPtr += dstRowBytes; |
191 | } |
192 | } |
193 | |
194 | void S9xBlitPixBlend2x1 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
195 | { |
196 | for (; height; height--) |
197 | { |
198 | uint16 *dP = (uint16 *) dstPtr, *bP = (uint16 *) srcPtr; |
199 | uint16 prev, curr; |
200 | |
201 | prev = *bP; |
202 | |
203 | for (int i = 0; i < (width >> 1); i++) |
204 | { |
205 | curr = *bP++; |
206 | *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); |
207 | *dP++ = curr; |
208 | prev = curr; |
209 | |
210 | curr = *bP++; |
211 | *dP++ = (prev & curr) + (((prev ^ curr) & highBitsMask) >> 1); |
212 | *dP++ = curr; |
213 | prev = curr; |
214 | } |
215 | |
216 | srcPtr += srcRowBytes; |
217 | dstPtr += dstRowBytes; |
218 | } |
219 | } |
220 | |
221 | void S9xBlitPixTV1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
222 | { |
223 | uint8 *dstPtr2 = dstPtr + dstRowBytes; |
224 | dstRowBytes <<= 1; |
225 | |
226 | for (; height; height--) |
227 | { |
228 | uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr; |
229 | uint32 product, darkened; |
230 | |
231 | for (int i = 0; i < (width >> 1); i++) |
232 | { |
233 | product = *dP1++ = *bP++; |
234 | darkened = (product = (product >> 1) & colorMask); |
235 | darkened += (product = (product >> 1) & colorMask); |
236 | *dP2++ = darkened; |
237 | } |
238 | |
239 | srcPtr += srcRowBytes; |
240 | dstPtr += dstRowBytes; |
241 | dstPtr2 += dstRowBytes; |
242 | } |
243 | } |
244 | |
245 | void S9xBlitPixTV2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
246 | { |
247 | uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta; |
248 | dstRowBytes <<= 1; |
249 | |
250 | for (; height; height--) |
251 | { |
252 | uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr; |
253 | uint32 currentPixel, nextPixel, currentDelta, nextDelta, colorA, colorB, product, darkened; |
254 | |
255 | for (int i = 0; i < (width >> 1) - 1; i++) |
256 | { |
257 | currentPixel = *bP; |
258 | currentDelta = *xP; |
259 | nextPixel = *(bP + 1); |
260 | nextDelta = *(xP + 1); |
261 | |
262 | if ((currentPixel != currentDelta) || (nextPixel != nextDelta)) |
263 | { |
264 | *xP = *bP; |
265 | |
266 | #ifdef MSB_FIRST |
267 | colorA = (currentPixel >> 16) & 0xFFFF; |
268 | colorB = (currentPixel ) & 0xFFFF; |
269 | #else |
270 | colorA = (currentPixel ) & 0xFFFF; |
271 | colorB = (currentPixel >> 16) & 0xFFFF; |
272 | #endif |
273 | |
274 | #ifdef MSB_FIRST |
275 | *dP1 = product = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); |
276 | #else |
277 | *dP1 = product = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); |
278 | #endif |
279 | |
280 | darkened = (product = ((product >> 1) & colorMask)); |
281 | darkened += (product = ((product >> 1) & colorMask)); |
282 | darkened += (product >> 1) & colorMask; |
283 | |
284 | *dP2 = darkened; |
285 | |
286 | #ifdef MSB_FIRST |
287 | colorA = (nextPixel >> 16) & 0xFFFF; |
288 | #else |
289 | colorA = (nextPixel ) & 0xFFFF; |
290 | #endif |
291 | |
292 | #ifdef MSB_FIRST |
293 | *(dP1 + 1) = product = (colorB << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); |
294 | #else |
295 | *(dP1 + 1) = product = (colorB ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); |
296 | #endif |
297 | |
298 | darkened = (product = ((product >> 1) & colorMask)); |
299 | darkened += (product = ((product >> 1) & colorMask)); |
300 | darkened += (product >> 1) & colorMask; |
301 | |
302 | *(dP2 + 1) = darkened; |
303 | } |
304 | |
305 | bP++; |
306 | xP++; |
307 | dP1 += 2; |
308 | dP2 += 2; |
309 | } |
310 | |
311 | // Last 2 Pixels |
312 | |
313 | currentPixel = *bP; |
314 | currentDelta = *xP; |
315 | |
316 | if (currentPixel != currentDelta) |
317 | { |
318 | *xP = *bP; |
319 | |
320 | #ifdef MSB_FIRST |
321 | colorA = (currentPixel >> 16) & 0xFFFF; |
322 | colorB = (currentPixel ) & 0xFFFF; |
323 | #else |
324 | colorA = (currentPixel ) & 0xFFFF; |
325 | colorB = (currentPixel >> 16) & 0xFFFF; |
326 | #endif |
327 | |
328 | #ifdef MSB_FIRST |
329 | *dP1 = product = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); |
330 | #else |
331 | *dP1 = product = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); |
332 | #endif |
333 | |
334 | darkened = (product = ((product >> 1) & colorMask)); |
335 | darkened += (product = ((product >> 1) & colorMask)); |
336 | darkened += (product >> 1) & colorMask; |
337 | |
338 | *dP2 = darkened; |
339 | |
340 | *(dP1 + 1) = product = (colorB << 16) | colorB; |
341 | |
342 | darkened = (product = ((product >> 1) & colorMask)); |
343 | darkened += (product = ((product >> 1) & colorMask)); |
344 | darkened += (product >> 1) & colorMask; |
345 | |
346 | *(dP2 + 1) = darkened; |
347 | } |
348 | |
349 | srcPtr += srcRowBytes; |
350 | deltaPtr += srcRowBytes; |
351 | dstPtr += dstRowBytes; |
352 | dstPtr2 += dstRowBytes; |
353 | } |
354 | } |
355 | |
356 | void S9xBlitPixMixedTV1x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
357 | { |
358 | uint8 *dstPtr2 = dstPtr + dstRowBytes, *srcPtr2 = srcPtr + srcRowBytes; |
359 | dstRowBytes <<= 1; |
360 | |
361 | for (; height > 1; height--) |
362 | { |
363 | uint16 *dP1 = (uint16 *) dstPtr, *dP2 = (uint16 *) dstPtr2, *bP1 = (uint16 *) srcPtr, *bP2 = (uint16 *) srcPtr2; |
364 | uint16 prev, next, mixed; |
365 | |
366 | for (int i = 0; i < width; i++) |
367 | { |
368 | prev = *bP1++; |
369 | next = *bP2++; |
370 | mixed = prev + next + ((prev ^ next) & lowPixelMask); |
371 | |
372 | *dP1++ = prev; |
373 | *dP2++ = (mixed >> 1) - (mixed >> 4 & qlowPixelMask); |
374 | } |
375 | |
376 | srcPtr += srcRowBytes; |
377 | srcPtr2 += srcRowBytes; |
378 | dstPtr += dstRowBytes; |
379 | dstPtr2 += dstRowBytes; |
380 | } |
381 | |
382 | // Last 1 line |
383 | |
384 | uint16 *dP1 = (uint16 *) dstPtr, *dP2 = (uint16 *) dstPtr2, *bP1 = (uint16 *) srcPtr; |
385 | uint16 prev, mixed; |
386 | |
387 | for (int i = 0; i < width; i++) |
388 | { |
389 | prev = *bP1++; |
390 | mixed = prev + ((prev ^ 0) & lowPixelMask); |
391 | |
392 | *dP1++ = prev; |
393 | *dP2++ = (mixed >> 1) - (mixed >> 4 & qlowPixelMask); |
394 | } |
395 | } |
396 | |
397 | void S9xBlitPixSmooth2x2 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
398 | { |
399 | uint8 *dstPtr2 = dstPtr + dstRowBytes, *deltaPtr = XDelta; |
400 | uint32 lastLinePix[SNES_WIDTH << 1]; |
401 | uint8 lastLineChg[SNES_WIDTH >> 1]; |
402 | int lineBytes = width << 1; |
403 | |
404 | dstRowBytes <<= 1; |
405 | |
406 | memset(lastLinePix, 0, sizeof(lastLinePix)); |
407 | memset(lastLineChg, 0, sizeof(lastLineChg)); |
408 | |
409 | for (; height; height--) |
410 | { |
411 | uint32 *dP1 = (uint32 *) dstPtr, *dP2 = (uint32 *) dstPtr2, *bP = (uint32 *) srcPtr, *xP = (uint32 *) deltaPtr; |
412 | uint32 *lL = lastLinePix; |
413 | uint8 *lC = lastLineChg; |
414 | uint32 currentPixel, nextPixel, currentDelta, nextDelta, lastPix, lastChg, thisChg, currentPixA, currentPixB, colorA, colorB, colorC; |
415 | uint16 savePixel; |
416 | |
417 | savePixel = *(uint16 *) (srcPtr + lineBytes); |
418 | *(uint16 *) (srcPtr + lineBytes) = *(uint16 *) (srcPtr + lineBytes - 2); |
419 | *(uint32 *) (deltaPtr + lineBytes) = *(uint32 *) (srcPtr + lineBytes); |
420 | |
421 | nextPixel = *bP++; |
422 | nextDelta = *xP++; |
423 | |
424 | for (int i = 0; i < (width >> 1); i++) |
425 | { |
426 | currentPixel = nextPixel; |
427 | currentDelta = nextDelta; |
428 | nextPixel = *bP++; |
429 | nextDelta = *xP++; |
430 | lastChg = *lC; |
431 | thisChg = (nextPixel - nextDelta) | (currentPixel - currentDelta); |
432 | |
433 | #ifdef MSB_FIRST |
434 | colorA = (currentPixel >> 16) & 0xFFFF; |
435 | colorB = (currentPixel ) & 0xFFFF; |
436 | colorC = (nextPixel >> 16) & 0xFFFF; |
437 | |
438 | currentPixA = (colorA << 16) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) ); |
439 | currentPixB = (colorB << 16) | ((((colorC >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorC & colorB & lowPixelMask)) ); |
440 | #else |
441 | colorA = (currentPixel ) & 0xFFFF; |
442 | colorB = (currentPixel >> 16) & 0xFFFF; |
443 | colorC = (nextPixel ) & 0xFFFF; |
444 | |
445 | currentPixA = (colorA ) | ((((colorA >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorA & colorB & lowPixelMask)) << 16); |
446 | currentPixB = (colorB ) | ((((colorC >> 1) & colorMask) + ((colorB >> 1) & colorMask) + (colorC & colorB & lowPixelMask)) << 16); |
447 | #endif |
448 | |
449 | if (thisChg | lastChg) |
450 | { |
451 | xP[-2] = currentPixel; |
452 | |
453 | lastPix = lL[0]; |
454 | dP1[0] = ((currentPixA >> 1) & colorMask) + ((lastPix >> 1) & colorMask) + (currentPixA & lastPix & lowPixelMask); |
455 | dP2[0] = currentPixA; |
456 | lL[0] = currentPixA; |
457 | |
458 | lastPix = lL[1]; |
459 | dP1[1] = ((currentPixB >> 1) & colorMask) + ((lastPix >> 1) & colorMask) + (currentPixB & lastPix & lowPixelMask); |
460 | dP2[1] = currentPixB; |
461 | lL[1] = currentPixB; |
462 | |
463 | *lC++ = (thisChg != 0); |
464 | } |
465 | else |
466 | { |
467 | lL[0] = currentPixA; |
468 | lL[1] = currentPixB; |
469 | *lC++ = 0; |
470 | } |
471 | |
472 | lL += 2; |
473 | dP2 += 2; |
474 | dP1 += 2; |
475 | } |
476 | |
477 | *(uint16 *) (srcPtr + lineBytes) = savePixel; |
478 | |
479 | srcPtr += srcRowBytes; |
480 | deltaPtr += srcRowBytes; |
481 | dstPtr += dstRowBytes; |
482 | dstPtr2 += dstRowBytes; |
483 | } |
484 | } |
485 | |
486 | void S9xBlitPixSuper2xSaI16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
487 | { |
488 | Super2xSaI(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); |
489 | } |
490 | |
491 | void S9xBlitPix2xSaI16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
492 | { |
493 | _2xSaI(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); |
494 | } |
495 | |
496 | void S9xBlitPixSuperEagle16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
497 | { |
498 | SuperEagle(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); |
499 | } |
500 | |
501 | void S9xBlitPixEPX16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
502 | { |
503 | EPX_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); |
504 | } |
505 | |
506 | void S9xBlitPixHQ2x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
507 | { |
508 | HQ2X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); |
509 | } |
510 | |
511 | void S9xBlitPixHQ3x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
512 | { |
513 | HQ3X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); |
514 | } |
515 | |
516 | void S9xBlitPixHQ4x16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
517 | { |
518 | HQ4X_16(srcPtr, srcRowBytes, dstPtr, dstRowBytes, width, height); |
519 | } |
520 | |
521 | void S9xBlitPixNTSC16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
522 | { |
523 | snes_ntsc_blit(ntsc, (SNES_NTSC_IN_T const *) srcPtr, srcRowBytes >> 1, 0, width, height, dstPtr, dstRowBytes); |
524 | } |
525 | |
526 | void S9xBlitPixHiResNTSC16 (uint8 *srcPtr, int srcRowBytes, uint8 *dstPtr, int dstRowBytes, int width, int height) |
527 | { |
528 | snes_ntsc_blit_hires(ntsc, (SNES_NTSC_IN_T const *) srcPtr, srcRowBytes >> 1, 0, width, height, dstPtr, dstRowBytes); |
529 | } |
530 | |