d07c171f |
1 | /* |
2 | Copyright (C) 2003 Rice1964 |
3 | |
4 | This program is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU General Public License |
6 | as published by the Free Software Foundation; either version 2 |
7 | of the License, or (at your option) any later version. |
8 | |
9 | This program is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
17 | |
18 | */ |
19 | |
20 | #include "Config.h" |
21 | #include "ConvertImage.h" |
22 | #include "RenderBase.h" |
23 | |
24 | ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ] = |
25 | { |
26 | // 4bpp 8bpp 16bpp 32bpp |
27 | { Convert4b, Convert8b, Convert16b, ConvertRGBA32 }, // RGBA |
28 | { NULL, NULL, ConvertYUV, NULL }, // YUV |
29 | { Convert4b, Convert8b, NULL, NULL }, // CI |
30 | { Convert4b, Convert8b, Convert16b, NULL }, // IA |
31 | { Convert4b, Convert8b, Convert16b, NULL }, // I |
32 | { NULL, NULL, NULL, NULL }, // ? |
33 | { NULL, NULL, NULL, NULL }, // ? |
34 | { NULL, NULL, NULL, NULL } // ? |
35 | }; |
36 | ConvertFunction gConvertFunctions[ 8 ][ 4 ] = |
37 | { |
38 | // 4bpp 8bpp 16bpp 32bpp |
39 | { ConvertCI4, ConvertCI8, ConvertRGBA16, ConvertRGBA32 }, // RGBA |
40 | { NULL, NULL, ConvertYUV, NULL }, // YUV |
41 | { ConvertCI4, ConvertCI8, NULL, NULL }, // CI |
42 | { ConvertIA4, ConvertIA8, ConvertIA16, NULL }, // IA |
43 | { ConvertI4, ConvertI8, ConvertIA16, NULL }, // I |
44 | { NULL, NULL, NULL, NULL }, // ? |
45 | { NULL, NULL, NULL, NULL }, // ? |
46 | { NULL, NULL, NULL, NULL } // ? |
47 | }; |
48 | |
49 | ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ] = |
50 | { |
51 | // 4bpp 8bpp 16bpp 32bpp |
52 | { ConvertCI4, ConvertCI8, ConvertRGBA16, ConvertRGBA32 }, // RGBA |
53 | { NULL, NULL, ConvertYUV, NULL }, // YUV |
54 | { ConvertCI4, ConvertCI8, NULL, NULL }, // CI |
55 | { ConvertCI4, ConvertCI8, ConvertIA16, NULL }, // IA |
56 | { ConvertCI4, ConvertCI8, ConvertIA16, NULL }, // I |
57 | { NULL, NULL, NULL, NULL }, // ? |
58 | { NULL, NULL, NULL, NULL }, // ? |
59 | { NULL, NULL, NULL, NULL } // ? |
60 | }; |
61 | |
62 | extern bool conkerSwapHack; |
63 | |
64 | void ConvertRGBA16(CTexture *pTexture, const TxtrInfo &tinfo) |
65 | { |
66 | DrawInfo dInfo; |
67 | |
68 | // Copy of the base pointer |
69 | uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); |
70 | |
71 | uint8 * pByteSrc = (uint8 *)pSrc; |
72 | if (!pTexture->StartUpdate(&dInfo)) |
73 | return; |
74 | |
75 | uint32 nFiddle; |
76 | |
77 | if (tinfo.bSwapped) |
78 | { |
79 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
80 | { |
81 | if ((y&1) == 0) |
82 | nFiddle = 0x2; |
83 | else |
84 | nFiddle = 0x2 | 0x4; |
85 | |
86 | // dwDst points to start of destination row |
87 | uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); |
88 | |
89 | // DWordOffset points to the current dword we're looking at |
90 | // (process 2 pixels at a time). May be a problem if we don't start on even pixel |
91 | uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); |
92 | |
93 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
94 | { |
95 | uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ nFiddle]; |
96 | |
97 | dwDst[x] = Convert555ToRGBA(w); |
98 | |
99 | // Increment word offset to point to the next two pixels |
100 | dwWordOffset += 2; |
101 | } |
102 | } |
103 | } |
104 | else |
105 | { |
106 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
107 | { |
108 | // dwDst points to start of destination row |
109 | uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); |
110 | |
111 | // DWordOffset points to the current dword we're looking at |
112 | // (process 2 pixels at a time). May be a problem if we don't start on even pixel |
113 | uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); |
114 | |
115 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
116 | { |
117 | uint16 w = *(uint16 *)&pByteSrc[dwWordOffset ^ 0x2]; |
118 | |
119 | dwDst[x] = Convert555ToRGBA(w); |
120 | |
121 | // Increment word offset to point to the next two pixels |
122 | dwWordOffset += 2; |
123 | } |
124 | } |
125 | } |
126 | |
127 | pTexture->EndUpdate(&dInfo); |
128 | pTexture->SetOthersVariables(); |
129 | } |
130 | |
131 | void ConvertRGBA32(CTexture *pTexture, const TxtrInfo &tinfo) |
132 | { |
133 | DrawInfo dInfo; |
134 | if (!pTexture->StartUpdate(&dInfo)) |
135 | return; |
136 | |
137 | uint32 * pSrc = (uint32*)(tinfo.pPhysicalAddress); |
138 | |
139 | if( options.bUseFullTMEM ) |
140 | { |
141 | Tile &tile = gRDP.tiles[tinfo.tileNo]; |
142 | |
143 | uint32 *pWordSrc; |
144 | if( tinfo.tileNo >= 0 ) |
145 | { |
146 | pWordSrc = (uint32*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; |
147 | |
148 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
149 | { |
150 | uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); |
151 | |
152 | uint32 nFiddle = ( y&1 )? 0x2 : 0; |
153 | int idx = tile.dwLine*4*y; |
154 | |
155 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) |
156 | { |
157 | uint32 w = pWordSrc[idx^nFiddle]; |
158 | uint8* psw = (uint8*)&w; |
159 | uint8* pdw = (uint8*)&dwDst[x]; |
160 | #ifdef HAVE_GLES0 |
161 | pdw[0] = psw[0]; // Red |
162 | pdw[1] = psw[1]; // Green |
163 | pdw[2] = psw[2]; // Blue |
164 | #else |
165 | pdw[0] = psw[2]; // Blue |
166 | pdw[1] = psw[1]; // Green |
167 | pdw[2] = psw[0]; // Red |
168 | #endif |
169 | pdw[3] = psw[3]; // Alpha |
170 | } |
171 | } |
172 | } |
173 | } |
174 | else |
175 | { |
176 | if (tinfo.bSwapped) |
177 | { |
178 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
179 | { |
180 | if ((y%2) == 0) |
181 | { |
182 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
183 | uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); |
184 | |
185 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
186 | { |
187 | #ifdef HAVE_GLES0 |
188 | pDst[0] = pS[3]; // Red |
189 | pDst[1] = pS[2]; // Green |
190 | pDst[2] = pS[1]; // Blue |
191 | #else |
192 | pDst[0] = pS[1]; // Blue |
193 | pDst[1] = pS[2]; // Green |
194 | pDst[2] = pS[3]; // Red |
195 | #endif |
196 | pDst[3] = pS[0]; // Alpha |
197 | pS+=4; |
198 | pDst+=4; |
199 | } |
200 | } |
201 | else |
202 | { |
203 | uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
204 | uint8 *pS = (uint8 *)pSrc; |
205 | int n; |
206 | |
207 | n = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); |
208 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
209 | { |
210 | #ifdef HAVE_GLES0 |
211 | *pDst++ = COLOR_RGBA(pS[(n+1)^0x8], |
212 | pS[(n+2)^0x8], |
213 | pS[(n+3)^0x8], |
214 | pS[(n+0)^0x8]); |
215 | #else |
216 | *pDst++ = COLOR_RGBA(pS[(n+3)^0x8], |
217 | pS[(n+2)^0x8], |
218 | pS[(n+1)^0x8], |
219 | pS[(n+0)^0x8]); |
220 | #endif |
221 | n += 4; |
222 | } |
223 | } |
224 | } |
225 | } |
226 | else |
227 | { |
228 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
229 | { |
230 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
231 | uint8 *pS = (uint8 *)pSrc + (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad*4); |
232 | |
233 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
234 | { |
235 | #ifdef HAVE_GLES0 |
236 | pDst[0] = pS[3]; // Red |
237 | pDst[1] = pS[2]; // Green |
238 | pDst[2] = pS[1]; // Blue |
239 | #else |
240 | pDst[0] = pS[1]; // Blue |
241 | pDst[1] = pS[2]; // Green |
242 | pDst[2] = pS[3]; // Red |
243 | #endif |
244 | pDst[3] = pS[0]; // Alpha |
245 | pS+=4; |
246 | pDst+=4; |
247 | } |
248 | } |
249 | } |
250 | } |
251 | |
252 | pTexture->EndUpdate(&dInfo); |
253 | pTexture->SetOthersVariables(); |
254 | } |
255 | |
256 | // E.g. Dear Mario text |
257 | // Copy, Score etc |
258 | void ConvertIA4(CTexture *pTexture, const TxtrInfo &tinfo) |
259 | { |
260 | DrawInfo dInfo; |
261 | uint32 nFiddle; |
262 | |
263 | uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); |
264 | |
265 | #ifdef DEBUGGER |
266 | if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); |
267 | #endif |
268 | |
269 | if (!pTexture->StartUpdate(&dInfo)) |
270 | return; |
271 | |
272 | if (tinfo.bSwapped) |
273 | { |
274 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
275 | { |
276 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
277 | |
278 | // For odd lines, swap words too |
279 | if ((y%2) == 0) |
280 | nFiddle = 0x3; |
281 | else |
282 | nFiddle = 0x7; |
283 | |
284 | |
285 | // This may not work if X is not even? |
286 | uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); |
287 | |
288 | if (tinfo.WidthToLoad == 1) |
289 | { |
290 | // corner case |
291 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
292 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
293 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
294 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
295 | *pDst++ = OneToEight[(b & 0x10) >> 4]; |
296 | } |
297 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
298 | { |
299 | // Do two pixels at a time |
300 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
301 | |
302 | // Even |
303 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
304 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
305 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
306 | *pDst++ = OneToEight[(b & 0x10) >> 4]; |
307 | // Odd |
308 | *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; |
309 | *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; |
310 | *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; |
311 | *pDst++ = OneToEight[(b & 0x01) ]; |
312 | |
313 | dwByteOffset++; |
314 | } |
315 | } |
316 | } |
317 | else |
318 | { |
319 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
320 | { |
321 | uint8 *pDst = (uint8 *)dInfo.lpSurface + (y * dInfo.lPitch); |
322 | |
323 | // This may not work if X is not even? |
324 | uint32 dwByteOffset = (y+tinfo.TopToLoad) * tinfo.Pitch + (tinfo.LeftToLoad/2); |
325 | |
326 | if (tinfo.WidthToLoad == 1) |
327 | { |
328 | // corner case |
329 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
330 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
331 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
332 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
333 | *pDst++ = OneToEight[(b & 0x10) >> 4]; |
334 | } |
335 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
336 | { |
337 | // Do two pixels at a time |
338 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
339 | |
340 | // Even |
341 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
342 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
343 | *pDst++ = ThreeToEight[(b & 0xE0) >> 5]; |
344 | *pDst++ = OneToEight[(b & 0x10) >> 4]; |
345 | // Odd |
346 | *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; |
347 | *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; |
348 | *pDst++ = ThreeToEight[(b & 0x0E) >> 1]; |
349 | *pDst++ = OneToEight[(b & 0x01) ]; |
350 | |
351 | dwByteOffset++; |
352 | } |
353 | } |
354 | } |
355 | |
356 | pTexture->EndUpdate(&dInfo); |
357 | pTexture->SetOthersVariables(); |
358 | |
359 | } |
360 | |
361 | // E.g Mario's head textures |
362 | void ConvertIA8(CTexture *pTexture, const TxtrInfo &tinfo) |
363 | { |
364 | DrawInfo dInfo; |
365 | uint32 nFiddle; |
366 | |
367 | uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); |
368 | |
369 | #ifdef DEBUGGER |
370 | if (((long long)pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); |
371 | #endif |
372 | |
373 | if (!pTexture->StartUpdate(&dInfo)) |
374 | return; |
375 | |
376 | if (tinfo.bSwapped) |
377 | { |
378 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
379 | { |
380 | // For odd lines, swap words too |
381 | if ((y%2) == 0) |
382 | nFiddle = 0x3; |
383 | else |
384 | nFiddle = 0x7; |
385 | |
386 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
387 | // Points to current byte |
388 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
389 | |
390 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
391 | { |
392 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
393 | uint8 I = FourToEight[(b & 0xf0)>>4]; |
394 | |
395 | *pDst++ = I; |
396 | *pDst++ = I; |
397 | *pDst++ = I; |
398 | *pDst++ = FourToEight[(b & 0x0f) ]; |
399 | |
400 | dwByteOffset++; |
401 | } |
402 | } |
403 | } |
404 | else |
405 | { |
406 | register const uint8* FourToEightArray = &FourToEight[0]; |
407 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
408 | { |
409 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
410 | |
411 | // Points to current byte |
412 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
413 | |
414 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
415 | { |
416 | register uint8 b = pSrc[(dwByteOffset++) ^ 0x3]; |
417 | uint8 I = *(FourToEightArray+(b>>4)); |
418 | |
419 | *pDst++ = I; |
420 | *pDst++ = I; |
421 | *pDst++ = I; |
422 | *pDst++ = *(FourToEightArray+(b&0xF)); |
423 | } |
424 | } |
425 | } |
426 | |
427 | pTexture->EndUpdate(&dInfo); |
428 | pTexture->SetOthersVariables(); |
429 | |
430 | } |
431 | |
432 | // E.g. camera's clouds, shadows |
433 | void ConvertIA16(CTexture *pTexture, const TxtrInfo &tinfo) |
434 | { |
435 | DrawInfo dInfo; |
436 | uint32 nFiddle; |
437 | |
438 | uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); |
439 | uint8 * pByteSrc = (uint8 *)pSrc; |
440 | |
441 | if (!pTexture->StartUpdate(&dInfo)) |
442 | return; |
443 | |
444 | if (tinfo.bSwapped) |
445 | { |
446 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
447 | { |
448 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
449 | |
450 | if ((y%2) == 0) |
451 | nFiddle = 0x2; |
452 | else |
453 | nFiddle = 0x4 | 0x2; |
454 | |
455 | // Points to current word |
456 | uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); |
457 | |
458 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
459 | { |
460 | uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^nFiddle]; |
461 | |
462 | *pDst++ = (uint8)(w >> 8); |
463 | *pDst++ = (uint8)(w >> 8); |
464 | *pDst++ = (uint8)(w >> 8); |
465 | *pDst++ = (uint8)(w & 0xFF); |
466 | |
467 | dwWordOffset += 2; |
468 | } |
469 | } |
470 | } |
471 | else |
472 | { |
473 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
474 | { |
475 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
476 | |
477 | // Points to current word |
478 | uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); |
479 | |
480 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
481 | { |
482 | uint16 w = *(uint16 *)&pByteSrc[dwWordOffset^0x2]; |
483 | |
484 | *pDst++ = (uint8)(w >> 8); |
485 | *pDst++ = (uint8)(w >> 8); |
486 | *pDst++ = (uint8)(w >> 8); |
487 | *pDst++ = (uint8)(w & 0xFF); |
488 | |
489 | dwWordOffset += 2; |
490 | } |
491 | } |
492 | } |
493 | |
494 | |
495 | pTexture->EndUpdate(&dInfo); |
496 | pTexture->SetOthersVariables(); |
497 | } |
498 | |
499 | |
500 | |
501 | // Used by MarioKart |
502 | void ConvertI4(CTexture *pTexture, const TxtrInfo &tinfo) |
503 | { |
504 | DrawInfo dInfo; |
505 | uint32 nFiddle; |
506 | |
507 | uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); |
508 | |
509 | #ifdef DEBUGGER |
510 | if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); |
511 | #endif |
512 | |
513 | if (!pTexture->StartUpdate(&dInfo)) |
514 | return; |
515 | |
516 | if (tinfo.bSwapped) |
517 | { |
518 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
519 | { |
520 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
521 | |
522 | // Might not work with non-even starting X |
523 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); |
524 | |
525 | // For odd lines, swap words too |
526 | if( !conkerSwapHack || (y&4) == 0 ) |
527 | { |
528 | if ((y%2) == 0) |
529 | nFiddle = 0x3; |
530 | else |
531 | nFiddle = 0x7; |
532 | } |
533 | else |
534 | { |
535 | if ((y%2) == 1) |
536 | nFiddle = 0x3; |
537 | else |
538 | nFiddle = 0x7; |
539 | } |
540 | |
541 | if (tinfo.WidthToLoad == 1) |
542 | { |
543 | // corner case |
544 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
545 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
546 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
547 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
548 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
549 | } |
550 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
551 | { |
552 | // two pixels at a time |
553 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
554 | |
555 | // Even |
556 | *pDst++ = FourToEight[(b & 0xF0)>>4]; // Other implementations seem to or in (b&0xF0)>>4 |
557 | *pDst++ = FourToEight[(b & 0xF0)>>4]; // why? |
558 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
559 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
560 | // Odd |
561 | *pDst++ = FourToEight[(b & 0x0F)]; |
562 | *pDst++ = FourToEight[(b & 0x0F)]; |
563 | *pDst++ = FourToEight[(b & 0x0F)]; |
564 | *pDst++ = FourToEight[(b & 0x0F)]; |
565 | |
566 | dwByteOffset++; |
567 | } |
568 | } |
569 | |
570 | conkerSwapHack = false; |
571 | } |
572 | else |
573 | { |
574 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
575 | { |
576 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
577 | |
578 | // Might not work with non-even starting X |
579 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); |
580 | |
581 | if (tinfo.WidthToLoad == 1) |
582 | { |
583 | // corner case |
584 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
585 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
586 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
587 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
588 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
589 | } |
590 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
591 | { |
592 | // two pixels at a time |
593 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
594 | |
595 | // Even |
596 | *pDst++ = FourToEight[(b & 0xF0)>>4]; // Other implementations seem to or in (b&0xF0)>>4 |
597 | *pDst++ = FourToEight[(b & 0xF0)>>4]; // why? |
598 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
599 | *pDst++ = FourToEight[(b & 0xF0)>>4]; |
600 | // Odd |
601 | *pDst++ = FourToEight[(b & 0x0F)]; |
602 | *pDst++ = FourToEight[(b & 0x0F)]; |
603 | *pDst++ = FourToEight[(b & 0x0F)]; |
604 | *pDst++ = FourToEight[(b & 0x0F)]; |
605 | |
606 | dwByteOffset++; |
607 | } |
608 | } |
609 | } |
610 | |
611 | pTexture->EndUpdate(&dInfo); |
612 | pTexture->SetOthersVariables(); |
613 | } |
614 | |
615 | // Used by MarioKart |
616 | void ConvertI8(CTexture *pTexture, const TxtrInfo &tinfo) |
617 | { |
618 | DrawInfo dInfo; |
619 | uint32 nFiddle; |
620 | |
621 | long long pSrc = (long long) tinfo.pPhysicalAddress; |
622 | if (!pTexture->StartUpdate(&dInfo)) |
623 | return; |
624 | |
625 | if (tinfo.bSwapped) |
626 | { |
627 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
628 | { |
629 | if ((y%2) == 0) |
630 | nFiddle = 0x3; |
631 | else |
632 | nFiddle = 0x7; |
633 | |
634 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
635 | |
636 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
637 | |
638 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
639 | { |
640 | uint8 b = *(uint8*)((pSrc+dwByteOffset)^nFiddle); |
641 | |
642 | *pDst++ = b; |
643 | *pDst++ = b; |
644 | *pDst++ = b; |
645 | *pDst++ = b; // Alpha not 255? |
646 | |
647 | dwByteOffset++; |
648 | } |
649 | } |
650 | } |
651 | else |
652 | { |
653 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
654 | { |
655 | uint8 *pDst = (uint8 *)dInfo.lpSurface + y * dInfo.lPitch; |
656 | |
657 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
658 | |
659 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
660 | { |
661 | uint8 b = *(uint8*)((pSrc+dwByteOffset)^0x3); |
662 | |
663 | *pDst++ = b; |
664 | *pDst++ = b; |
665 | *pDst++ = b; |
666 | *pDst++ = b; // Alpha not 255? |
667 | |
668 | dwByteOffset++; |
669 | } |
670 | } |
671 | } |
672 | |
673 | pTexture->EndUpdate(&dInfo); |
674 | pTexture->SetOthersVariables(); |
675 | |
676 | } |
677 | |
678 | //***************************************************************************** |
679 | // Convert CI4 images. We need to switch on the palette type |
680 | //***************************************************************************** |
681 | void ConvertCI4( CTexture * p_texture, const TxtrInfo & tinfo ) |
682 | { |
683 | if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) |
684 | { |
685 | ConvertCI4_RGBA16( p_texture, tinfo ); |
686 | } |
687 | else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) |
688 | { |
689 | ConvertCI4_IA16( p_texture, tinfo ); |
690 | } |
691 | } |
692 | |
693 | //***************************************************************************** |
694 | // Convert CI8 images. We need to switch on the palette type |
695 | //***************************************************************************** |
696 | void ConvertCI8( CTexture * p_texture, const TxtrInfo & tinfo ) |
697 | { |
698 | if ( tinfo.TLutFmt == TLUT_FMT_RGBA16 ) |
699 | { |
700 | ConvertCI8_RGBA16( p_texture, tinfo ); |
701 | } |
702 | else if ( tinfo.TLutFmt == TLUT_FMT_IA16 ) |
703 | { |
704 | ConvertCI8_IA16( p_texture, tinfo ); |
705 | } |
706 | } |
707 | |
708 | // Used by Starfox intro |
709 | void ConvertCI4_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo) |
710 | { |
711 | DrawInfo dInfo; |
712 | uint32 nFiddle; |
713 | |
714 | uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); |
715 | uint16 * pPal = (uint16 *)tinfo.PalAddress; |
716 | bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); |
717 | |
718 | if (!pTexture->StartUpdate(&dInfo)) |
719 | return; |
720 | |
721 | if (tinfo.bSwapped) |
722 | { |
723 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
724 | { |
725 | if ((y%2) == 0) |
726 | nFiddle = 0x3; |
727 | else |
728 | nFiddle = 0x7; |
729 | |
730 | uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
731 | |
732 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch); |
733 | |
734 | if (tinfo.WidthToLoad == 1) |
735 | { |
736 | // corner case |
737 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
738 | uint8 bhi = (b&0xf0)>>4; |
739 | *pDst = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
740 | if( bIgnoreAlpha ) |
741 | { |
742 | *pDst |= 0xFF000000; |
743 | } |
744 | } |
745 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
746 | { |
747 | // two at a time |
748 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
749 | |
750 | uint8 bhi = (b&0xf0)>>4; |
751 | uint8 blo = (b&0x0f); |
752 | |
753 | pDst[0] = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
754 | pDst[1] = Convert555ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! |
755 | |
756 | if( bIgnoreAlpha ) |
757 | { |
758 | pDst[0] |= 0xFF000000; |
759 | pDst[1] |= 0xFF000000; |
760 | } |
761 | |
762 | pDst+=2; |
763 | |
764 | dwByteOffset++; |
765 | } |
766 | } |
767 | } |
768 | else |
769 | { |
770 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
771 | { |
772 | uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
773 | |
774 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); |
775 | |
776 | if (tinfo.WidthToLoad == 1) |
777 | { |
778 | // corner case |
779 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
780 | uint8 bhi = (b&0xf0)>>4; |
781 | *pDst = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
782 | if( bIgnoreAlpha ) |
783 | { |
784 | *pDst |= 0xFF000000; |
785 | } |
786 | } |
787 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
788 | { |
789 | // two at a time |
790 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
791 | |
792 | uint8 bhi = (b&0xf0)>>4; |
793 | uint8 blo = (b&0x0f); |
794 | |
795 | pDst[0] = Convert555ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
796 | pDst[1] = Convert555ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! |
797 | |
798 | if( bIgnoreAlpha ) |
799 | { |
800 | pDst[0] |= 0xFF000000; |
801 | pDst[1] |= 0xFF000000; |
802 | } |
803 | |
804 | pDst+=2; |
805 | |
806 | dwByteOffset++; |
807 | } |
808 | } |
809 | } |
810 | pTexture->EndUpdate(&dInfo); |
811 | pTexture->SetOthersVariables(); |
812 | } |
813 | |
814 | // Used by Starfox intro |
815 | void ConvertCI4_IA16(CTexture *pTexture, const TxtrInfo &tinfo) |
816 | { |
817 | DrawInfo dInfo; |
818 | uint32 nFiddle; |
819 | |
820 | uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); |
821 | |
822 | #ifdef DEBUGGER |
823 | if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); |
824 | #endif |
825 | |
826 | uint16 * pPal = (uint16 *)tinfo.PalAddress; |
827 | bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); |
828 | |
829 | if (!pTexture->StartUpdate(&dInfo)) |
830 | return; |
831 | |
832 | if (tinfo.bSwapped) |
833 | { |
834 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
835 | { |
836 | if ((y%2) == 0) |
837 | nFiddle = 0x3; |
838 | else |
839 | nFiddle = 0x7; |
840 | |
841 | uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
842 | |
843 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); |
844 | |
845 | if (tinfo.WidthToLoad == 1) |
846 | { |
847 | // corner case |
848 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
849 | uint8 bhi = (b&0xf0)>>4; |
850 | *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
851 | if( bIgnoreAlpha ) |
852 | *pDst |= 0xFF000000; |
853 | } |
854 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
855 | { |
856 | // two at a time |
857 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
858 | |
859 | uint8 bhi = (b&0xf0)>>4; |
860 | uint8 blo = (b&0x0f); |
861 | |
862 | pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
863 | pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! |
864 | |
865 | if( bIgnoreAlpha ) |
866 | { |
867 | pDst[0] |= 0xFF000000; |
868 | pDst[1] |= 0xFF000000; |
869 | } |
870 | |
871 | pDst+=2; |
872 | |
873 | dwByteOffset++; |
874 | } |
875 | } |
876 | } |
877 | else |
878 | { |
879 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
880 | { |
881 | uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
882 | |
883 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); |
884 | |
885 | if (tinfo.WidthToLoad == 1) |
886 | { |
887 | // corner case |
888 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
889 | uint8 bhi = (b&0xf0)>>4; |
890 | *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
891 | if( bIgnoreAlpha ) |
892 | *pDst |= 0xFF000000; |
893 | } |
894 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2) |
895 | { |
896 | // two pixels at a time |
897 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
898 | |
899 | uint8 bhi = (b&0xf0)>>4; |
900 | uint8 blo = (b&0x0f); |
901 | |
902 | pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); // Remember palette is in different endian order! |
903 | pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); // Remember palette is in different endian order! |
904 | |
905 | if( bIgnoreAlpha ) |
906 | { |
907 | pDst[0] |= 0xFF000000; |
908 | pDst[1] |= 0xFF000000; |
909 | } |
910 | |
911 | pDst+=2; |
912 | |
913 | dwByteOffset++; |
914 | } |
915 | } |
916 | } |
917 | pTexture->EndUpdate(&dInfo); |
918 | pTexture->SetOthersVariables(); |
919 | } |
920 | |
921 | |
922 | // Used by MarioKart for Cars etc |
923 | void ConvertCI8_RGBA16(CTexture *pTexture, const TxtrInfo &tinfo) |
924 | { |
925 | DrawInfo dInfo; |
926 | uint32 nFiddle; |
927 | |
928 | uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); |
929 | |
930 | #ifdef DEBUGGER |
931 | if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); |
932 | #endif |
933 | |
934 | uint16 * pPal = (uint16 *)tinfo.PalAddress; |
935 | bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); |
936 | |
937 | if (!pTexture->StartUpdate(&dInfo)) |
938 | return; |
939 | |
940 | if (tinfo.bSwapped) |
941 | { |
942 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
943 | { |
944 | if ((y%2) == 0) |
945 | nFiddle = 0x3; |
946 | else |
947 | nFiddle = 0x7; |
948 | |
949 | uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
950 | |
951 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
952 | |
953 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
954 | { |
955 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
956 | |
957 | *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order! |
958 | |
959 | if( bIgnoreAlpha ) |
960 | { |
961 | *(pDst-1) |= 0xFF000000; |
962 | } |
963 | |
964 | dwByteOffset++; |
965 | } |
966 | } |
967 | } |
968 | else |
969 | { |
970 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
971 | { |
972 | uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
973 | |
974 | int dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
975 | |
976 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
977 | { |
978 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
979 | |
980 | *pDst++ = Convert555ToRGBA(pPal[b^1]); // Remember palette is in different endian order! |
981 | if( bIgnoreAlpha ) |
982 | { |
983 | *(pDst-1) |= 0xFF000000; |
984 | } |
985 | |
986 | dwByteOffset++; |
987 | } |
988 | } |
989 | } |
990 | |
991 | pTexture->EndUpdate(&dInfo); |
992 | pTexture->SetOthersVariables(); |
993 | |
994 | } |
995 | |
996 | |
997 | // Used by MarioKart for Cars etc |
998 | void ConvertCI8_IA16(CTexture *pTexture, const TxtrInfo &tinfo) |
999 | { |
1000 | DrawInfo dInfo; |
1001 | uint32 nFiddle; |
1002 | |
1003 | uint8 * pSrc = (uint8*)(tinfo.pPhysicalAddress); |
1004 | |
1005 | #ifdef DEBUGGER |
1006 | if (((long long) pSrc) % 4) TRACE0("Texture src addr is not aligned to 4 bytes, check me"); |
1007 | #endif |
1008 | |
1009 | uint16 * pPal = (uint16 *)tinfo.PalAddress; |
1010 | bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); |
1011 | |
1012 | if (!pTexture->StartUpdate(&dInfo)) |
1013 | return; |
1014 | |
1015 | if (tinfo.bSwapped) |
1016 | { |
1017 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
1018 | { |
1019 | if ((y%2) == 0) |
1020 | nFiddle = 0x3; |
1021 | else |
1022 | nFiddle = 0x7; |
1023 | |
1024 | uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
1025 | |
1026 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
1027 | |
1028 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
1029 | { |
1030 | uint8 b = pSrc[dwByteOffset ^ nFiddle]; |
1031 | |
1032 | *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order! |
1033 | if( bIgnoreAlpha ) |
1034 | { |
1035 | *(pDst-1) |= 0xFF000000; |
1036 | } |
1037 | |
1038 | dwByteOffset++; |
1039 | } |
1040 | } |
1041 | } |
1042 | else |
1043 | { |
1044 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
1045 | { |
1046 | uint32 *pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
1047 | |
1048 | uint32 dwByteOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
1049 | |
1050 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++) |
1051 | { |
1052 | uint8 b = pSrc[dwByteOffset ^ 0x3]; |
1053 | |
1054 | *pDst++ = ConvertIA16ToRGBA(pPal[b^1]); // Remember palette is in different endian order! |
1055 | if( bIgnoreAlpha ) |
1056 | { |
1057 | *(pDst-1) |= 0xFF000000; |
1058 | } |
1059 | |
1060 | dwByteOffset++; |
1061 | } |
1062 | } |
1063 | } |
1064 | |
1065 | pTexture->EndUpdate(&dInfo); |
1066 | pTexture->SetOthersVariables(); |
1067 | } |
1068 | |
1069 | void ConvertYUV(CTexture *pTexture, const TxtrInfo &tinfo) |
1070 | { |
1071 | DrawInfo dInfo; |
1072 | if (!pTexture->StartUpdate(&dInfo)) |
1073 | return; |
1074 | |
1075 | uint32 x, y; |
1076 | uint32 nFiddle; |
1077 | |
1078 | if( options.bUseFullTMEM ) |
1079 | { |
1080 | Tile &tile = gRDP.tiles[tinfo.tileNo]; |
1081 | |
1082 | uint16 * pSrc; |
1083 | if( tinfo.tileNo >= 0 ) |
1084 | pSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; |
1085 | else |
1086 | pSrc = (uint16*)(tinfo.pPhysicalAddress); |
1087 | |
1088 | uint8 * pByteSrc = (uint8 *)pSrc; |
1089 | for (y = 0; y < tinfo.HeightToLoad; y++) |
1090 | { |
1091 | nFiddle = ( y&1 )? 0x4 : 0; |
1092 | int dwWordOffset = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); |
1093 | uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); |
1094 | |
1095 | for (x = 0; x < tinfo.WidthToLoad/2; x++) |
1096 | { |
1097 | int y0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; |
1098 | int y1 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; |
1099 | int u0 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; |
1100 | int v0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; |
1101 | |
1102 | dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); |
1103 | dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); |
1104 | |
1105 | dwWordOffset += 4; |
1106 | } |
1107 | } |
1108 | } |
1109 | else |
1110 | { |
1111 | uint16 * pSrc = (uint16*)(tinfo.pPhysicalAddress); |
1112 | uint8 * pByteSrc = (uint8 *)pSrc; |
1113 | |
1114 | if (tinfo.bSwapped) |
1115 | { |
1116 | for (y = 0; y < tinfo.HeightToLoad; y++) |
1117 | { |
1118 | if ((y&1) == 0) |
1119 | nFiddle = 0x3; |
1120 | else |
1121 | nFiddle = 0x7; |
1122 | |
1123 | // dwDst points to start of destination row |
1124 | uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); |
1125 | |
1126 | // DWordOffset points to the current dword we're looking at |
1127 | // (process 2 pixels at a time). May be a problem if we don't start on even pixel |
1128 | uint32 dwWordOffset = ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad * 2); |
1129 | |
1130 | for (x = 0; x < tinfo.WidthToLoad/2; x++) |
1131 | { |
1132 | int y0 = *(uint8*)&pByteSrc[(dwWordOffset+2)^nFiddle]; |
1133 | int v0 = *(uint8*)&pByteSrc[(dwWordOffset+1)^nFiddle]; |
1134 | int y1 = *(uint8*)&pByteSrc[(dwWordOffset )^nFiddle]; |
1135 | int u0 = *(uint8*)&pByteSrc[(dwWordOffset+3)^nFiddle]; |
1136 | |
1137 | dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); |
1138 | dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); |
1139 | |
1140 | dwWordOffset += 4; |
1141 | } |
1142 | } |
1143 | } |
1144 | else |
1145 | { |
1146 | for (y = 0; y < tinfo.HeightToLoad; y++) |
1147 | { |
1148 | // dwDst points to start of destination row |
1149 | uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); |
1150 | uint32 dwByteOffset = y * 32; |
1151 | |
1152 | for (x = 0; x < tinfo.WidthToLoad/2; x++) |
1153 | { |
1154 | int y0 = *(uint8*)&pByteSrc[(dwByteOffset+2)]; |
1155 | int v0 = *(uint8*)&pByteSrc[(dwByteOffset+1)]; |
1156 | int y1 = *(uint8*)&pByteSrc[(dwByteOffset )]; |
1157 | int u0 = *(uint8*)&pByteSrc[(dwByteOffset+3)]; |
1158 | |
1159 | dwDst[x*2+0] = ConvertYUV16ToR8G8B8(y0,u0,v0); |
1160 | dwDst[x*2+1] = ConvertYUV16ToR8G8B8(y1,u0,v0); |
1161 | |
1162 | // Increment word offset to point to the next two pixels |
1163 | dwByteOffset += 4; |
1164 | } |
1165 | } |
1166 | } |
1167 | } |
1168 | |
1169 | pTexture->EndUpdate(&dInfo); |
1170 | pTexture->SetOthersVariables(); |
1171 | } |
1172 | |
1173 | uint32 ConvertYUV16ToR8G8B8(int Y, int U, int V) |
1174 | { |
1175 | /* |
1176 | int R = int(g_convc0 *(Y-16) + g_convc1 * V); |
1177 | int G = int(g_convc0 *(Y-16) + g_convc2 * U - g_convc3 * V); |
1178 | int B = int(g_convc0 *(Y-16) + g_convc4 * U); |
1179 | */ |
1180 | |
1181 | Y += 80; |
1182 | int R = int(Y + (1.370705f * (V-128))); |
1183 | int G = int(Y - (0.698001f * (V-128)) - (0.337633f * (U-128))); |
1184 | int B = int(Y + (1.732446f * (U-128))); |
1185 | |
1186 | R = R < 0 ? 0 : (R>255 ? 255 : R); |
1187 | G = G < 0 ? 0 : (G>255 ? 255 : G); |
1188 | B = B < 0 ? 0 : (B>255 ? 255 : B); |
1189 | |
1190 | return COLOR_RGBA(R, G, B, 0xFF); |
1191 | } |
1192 | |
1193 | |
1194 | // Used by Starfox intro |
1195 | void Convert4b(CTexture *pTexture, const TxtrInfo &tinfo) |
1196 | { |
1197 | DrawInfo dInfo; |
1198 | |
1199 | if (!pTexture->StartUpdate(&dInfo)) |
1200 | return; |
1201 | |
1202 | uint16 * pPal = (uint16 *)tinfo.PalAddress; |
1203 | bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); |
1204 | if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); |
1205 | |
1206 | Tile &tile = gRDP.tiles[tinfo.tileNo]; |
1207 | |
1208 | uint8 *pByteSrc = tinfo.tileNo >= 0 ? (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem] : (uint8*)(tinfo.pPhysicalAddress); |
1209 | |
1210 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
1211 | { |
1212 | uint32 nFiddle; |
1213 | if( tinfo.tileNo < 0 ) |
1214 | { |
1215 | if (tinfo.bSwapped) |
1216 | { |
1217 | if ((y%2) == 0) |
1218 | nFiddle = 0x3; |
1219 | else |
1220 | nFiddle = 0x7; |
1221 | } |
1222 | else |
1223 | { |
1224 | nFiddle = 3; |
1225 | } |
1226 | } |
1227 | else |
1228 | { |
1229 | nFiddle = ( y&1 )? 0x4 : 0; |
1230 | } |
1231 | |
1232 | uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
1233 | int idx = tinfo.tileNo>=0 ? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + (tinfo.LeftToLoad / 2); |
1234 | |
1235 | if (tinfo.WidthToLoad == 1) |
1236 | { |
1237 | // corner case |
1238 | uint8 b = pByteSrc[idx^nFiddle]; |
1239 | uint8 bhi = (b&0xf0)>>4; |
1240 | if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) |
1241 | { |
1242 | if( tinfo.TLutFmt == TLUT_FMT_IA16 ) |
1243 | { |
1244 | if( tinfo.tileNo>=0 ) |
1245 | *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); |
1246 | else |
1247 | *pDst = ConvertIA16ToRGBA(pPal[bhi^1]); |
1248 | } |
1249 | else |
1250 | { |
1251 | if( tinfo.tileNo>=0 ) |
1252 | *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); |
1253 | else |
1254 | *pDst = Convert555ToRGBA(pPal[bhi^1]); |
1255 | } |
1256 | } |
1257 | else if( tinfo.Format == TXT_FMT_IA ) |
1258 | *pDst = ConvertIA4ToRGBA(b>>4); |
1259 | else // if( tinfo.Format == TXT_FMT_I ) |
1260 | *pDst = ConvertI4ToRGBA(b>>4); |
1261 | if( bIgnoreAlpha ) |
1262 | *pDst |= 0xFF000000; |
1263 | } |
1264 | else for (uint32 x = 0; x < tinfo.WidthToLoad; x+=2, idx++) |
1265 | { |
1266 | // two pixels at a time |
1267 | uint8 b = pByteSrc[idx^nFiddle]; |
1268 | uint8 bhi = (b&0xf0)>>4; |
1269 | uint8 blo = (b&0x0f); |
1270 | |
1271 | if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) |
1272 | { |
1273 | if( tinfo.TLutFmt == TLUT_FMT_IA16 ) |
1274 | { |
1275 | if( tinfo.tileNo>=0 ) |
1276 | { |
1277 | pDst[0] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); |
1278 | pDst[1] = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); |
1279 | } |
1280 | else |
1281 | { |
1282 | pDst[0] = ConvertIA16ToRGBA(pPal[bhi^1]); |
1283 | pDst[1] = ConvertIA16ToRGBA(pPal[blo^1]); |
1284 | } |
1285 | } |
1286 | else |
1287 | { |
1288 | if( tinfo.tileNo>=0 ) |
1289 | { |
1290 | pDst[0] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(bhi<<2)]); |
1291 | pDst[1] = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+tinfo.Palette*0x40+(blo<<2)]); |
1292 | } |
1293 | else |
1294 | { |
1295 | pDst[0] = Convert555ToRGBA(pPal[bhi^1]); |
1296 | pDst[1] = Convert555ToRGBA(pPal[blo^1]); |
1297 | } |
1298 | } |
1299 | } |
1300 | else if( tinfo.Format == TXT_FMT_IA ) |
1301 | { |
1302 | pDst[0] = ConvertIA4ToRGBA(b>>4); |
1303 | pDst[1] = ConvertIA4ToRGBA(b&0xF); |
1304 | } |
1305 | else // if( tinfo.Format == TXT_FMT_I ) |
1306 | { |
1307 | pDst[0] = ConvertI4ToRGBA(b>>4); |
1308 | pDst[1] = ConvertI4ToRGBA(b&0xF); |
1309 | } |
1310 | |
1311 | if( bIgnoreAlpha ) |
1312 | { |
1313 | pDst[0] |= 0xFF000000; |
1314 | pDst[1] |= 0xFF000000; |
1315 | } |
1316 | pDst+=2; |
1317 | } |
1318 | } |
1319 | |
1320 | pTexture->EndUpdate(&dInfo); |
1321 | pTexture->SetOthersVariables(); |
1322 | } |
1323 | |
1324 | void Convert8b(CTexture *pTexture, const TxtrInfo &tinfo) |
1325 | { |
1326 | DrawInfo dInfo; |
1327 | if (!pTexture->StartUpdate(&dInfo)) |
1328 | return; |
1329 | |
1330 | uint16 * pPal = (uint16 *)tinfo.PalAddress; |
1331 | bool bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_UNKNOWN); |
1332 | if( tinfo.Format <= TXT_FMT_CI ) bIgnoreAlpha = (tinfo.TLutFmt==TLUT_FMT_NONE); |
1333 | |
1334 | Tile &tile = gRDP.tiles[tinfo.tileNo]; |
1335 | |
1336 | uint8 *pByteSrc; |
1337 | if( tinfo.tileNo >= 0 ) |
1338 | { |
1339 | pByteSrc = (uint8*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; |
1340 | } |
1341 | else |
1342 | { |
1343 | pByteSrc = (uint8*)(tinfo.pPhysicalAddress); |
1344 | } |
1345 | |
1346 | |
1347 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
1348 | { |
1349 | uint32 * pDst = (uint32 *)((uint8 *)dInfo.lpSurface + y * dInfo.lPitch); |
1350 | |
1351 | uint32 nFiddle; |
1352 | if( tinfo.tileNo < 0 ) |
1353 | { |
1354 | if (tinfo.bSwapped) |
1355 | { |
1356 | if ((y%2) == 0) |
1357 | nFiddle = 0x3; |
1358 | else |
1359 | nFiddle = 0x7; |
1360 | } |
1361 | else |
1362 | { |
1363 | nFiddle = 3; |
1364 | } |
1365 | } |
1366 | else |
1367 | { |
1368 | nFiddle = ( y&1 )? 0x4 : 0; |
1369 | } |
1370 | |
1371 | |
1372 | int idx = tinfo.tileNo>=0? tile.dwLine*8*y : ((y+tinfo.TopToLoad) * tinfo.Pitch) + tinfo.LeftToLoad; |
1373 | |
1374 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) |
1375 | { |
1376 | uint8 b = pByteSrc[idx^nFiddle]; |
1377 | |
1378 | if( gRDP.otherMode.text_tlut>=2 || ( tinfo.Format != TXT_FMT_IA && tinfo.Format != TXT_FMT_I) ) |
1379 | { |
1380 | if( tinfo.TLutFmt == TLUT_FMT_IA16 ) |
1381 | { |
1382 | if( tinfo.tileNo>=0 ) |
1383 | *pDst = ConvertIA16ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); |
1384 | else |
1385 | *pDst = ConvertIA16ToRGBA(pPal[b^1]); |
1386 | } |
1387 | else |
1388 | { |
1389 | if( tinfo.tileNo>=0 ) |
1390 | *pDst = Convert555ToRGBA(g_Tmem.g_Tmem16bit[0x400+(b<<2)]); |
1391 | else |
1392 | *pDst = Convert555ToRGBA(pPal[b^1]); |
1393 | } |
1394 | } |
1395 | else if( tinfo.Format == TXT_FMT_IA ) |
1396 | { |
1397 | uint8 I = FourToEight[(b & 0xf0)>>4]; |
1398 | uint8 * pByteDst = (uint8*)pDst; |
1399 | pByteDst[0] = I; |
1400 | pByteDst[1] = I; |
1401 | pByteDst[2] = I; |
1402 | pByteDst[3] = FourToEight[(b & 0x0f) ]; |
1403 | } |
1404 | else // if( tinfo.Format == TXT_FMT_I ) |
1405 | { |
1406 | uint8 * pByteDst = (uint8*)pDst; |
1407 | pByteDst[0] = b; |
1408 | pByteDst[1] = b; |
1409 | pByteDst[2] = b; |
1410 | pByteDst[3] = b; |
1411 | } |
1412 | |
1413 | if( bIgnoreAlpha ) |
1414 | { |
1415 | *pDst |= 0xFF000000; |
1416 | } |
1417 | pDst++; |
1418 | } |
1419 | } |
1420 | |
1421 | pTexture->EndUpdate(&dInfo); |
1422 | pTexture->SetOthersVariables(); |
1423 | } |
1424 | |
1425 | |
1426 | void Convert16b(CTexture *pTexture, const TxtrInfo &tinfo) |
1427 | { |
1428 | DrawInfo dInfo; |
1429 | if (!pTexture->StartUpdate(&dInfo)) |
1430 | return; |
1431 | |
1432 | Tile &tile = gRDP.tiles[tinfo.tileNo]; |
1433 | |
1434 | uint16 *pWordSrc; |
1435 | if( tinfo.tileNo >= 0 ) |
1436 | pWordSrc = (uint16*)&g_Tmem.g_Tmem64bit[tile.dwTMem]; |
1437 | else |
1438 | pWordSrc = (uint16*)(tinfo.pPhysicalAddress); |
1439 | |
1440 | |
1441 | for (uint32 y = 0; y < tinfo.HeightToLoad; y++) |
1442 | { |
1443 | uint32 * dwDst = (uint32 *)((uint8 *)dInfo.lpSurface + y*dInfo.lPitch); |
1444 | |
1445 | uint32 nFiddle; |
1446 | if( tinfo.tileNo < 0 ) |
1447 | { |
1448 | if (tinfo.bSwapped) |
1449 | { |
1450 | if ((y&1) == 0) |
1451 | nFiddle = 0x1; |
1452 | else |
1453 | nFiddle = 0x3; |
1454 | } |
1455 | else |
1456 | { |
1457 | nFiddle = 0x1; |
1458 | } |
1459 | } |
1460 | else |
1461 | { |
1462 | nFiddle = ( y&1 )? 0x2 : 0; |
1463 | } |
1464 | |
1465 | |
1466 | int idx = tinfo.tileNo>=0? tile.dwLine*4*y : (((y+tinfo.TopToLoad) * tinfo.Pitch)>>1) + tinfo.LeftToLoad; |
1467 | |
1468 | for (uint32 x = 0; x < tinfo.WidthToLoad; x++, idx++) |
1469 | { |
1470 | uint16 w = pWordSrc[idx^nFiddle]; |
1471 | uint16 w2 = tinfo.tileNo>=0? ((w>>8)|(w<<8)) : w; |
1472 | |
1473 | if( tinfo.Format == TXT_FMT_RGBA ) |
1474 | { |
1475 | dwDst[x] = Convert555ToRGBA(w2); |
1476 | } |
1477 | else if( tinfo.Format == TXT_FMT_YUV ) |
1478 | { |
1479 | } |
1480 | else if( tinfo.Format >= TXT_FMT_IA ) |
1481 | { |
1482 | uint8 * pByteDst = (uint8*)&dwDst[x]; |
1483 | *pByteDst++ = (uint8)(w2 >> 8); |
1484 | *pByteDst++ = (uint8)(w2 >> 8); |
1485 | *pByteDst++ = (uint8)(w2 >> 8); |
1486 | *pByteDst++ = (uint8)(w2 & 0xFF); |
1487 | } |
1488 | } |
1489 | } |
1490 | |
1491 | pTexture->EndUpdate(&dInfo); |
1492 | pTexture->SetOthersVariables(); |
1493 | } |
1494 | |