1 #include "neogeo.h"
2 
3 UINT8* NeoTextROMBIOS;
4 UINT8* NeoTextROM[MAX_SLOT];
5 
6 INT32 nNeoTextROMSize[MAX_SLOT] = { 0, };
7 bool bBIOSTextROMEnabled;
8 
9 static UINT8* NeoTextROMCurrent;
10 
11 static INT8* NeoTextTileAttrib[MAX_SLOT] = { NULL, };
12 static INT8* NeoTextTileAttribBIOS = NULL;
13 static INT8* NeoTextTileAttribActive = NULL;
14 static INT32 nBankswitch[MAX_SLOT] = { 0, };
15 
16 static INT32 nBankLookupAddress[40];
17 static INT32 nBankLookupShift[40];
18 
19 static UINT8* pTile;
20 static UINT8* pTileData;
21 static UINT32* pTilePalette;
22 static UINT32 nTransparent;
23 
24 typedef void (*RenderTileFunction)();
25 static RenderTileFunction RenderTile;
26 
27 static INT32 nLastBPP = 0;
28 
29 static INT32 nMinX, nMaxX;
30 
alpha_blend(UINT32 d,UINT32 s,UINT32 p)31 static inline UINT32 alpha_blend(UINT32 d, UINT32 s, UINT32 p)
32 {
33 	INT32 a = 255 - p;
34 
35 	return (((((s & 0xff00ff) * p) + ((d & 0xff00ff) * a)) & 0xff00ff00) +
36 		((((s & 0x00ff00) * p) + ((d & 0x00ff00) * a)) & 0x00ff0000)) >> 8;
37 }
38 
39 #define BPP 16
40  #include "neo_text_render.h"
41 #undef BPP
42 
43 #define BPP 24
44  #include "neo_text_render.h"
45 #undef BPP
46 
47 #define BPP 32
48  #include "neo_text_render.h"
49 #undef BPP
50 
NeoRenderText()51 INT32 NeoRenderText()
52 {
53 	INT32 x, y;
54 	UINT8* pTextROM;
55 	INT8* pTileAttrib;
56 	UINT8* pCurrentRow = pBurnDraw;
57 	UINT32* pTextPalette = NeoPalette;
58 	UINT32 nTileDown = nBurnPitch << 3;
59 	UINT32 nTileLeft = nBurnBpp << 3;
60 	UINT16* pTileRow = (UINT16*)(NeoGraphicsRAM + 0xE000);
61 
62 	if (!(nBurnLayer & 2)) {
63 		return 0;
64 	}
65 
66 	if (nLastBPP != nBurnBpp ) {
67 		nLastBPP = nBurnBpp;
68 
69 		switch (nBurnBpp) {
70 			case 2:
71 				RenderTile = *RenderTile16;
72 				break;
73 			case 3:
74 				RenderTile = *RenderTile24;
75 				break;
76 			case 4:
77 				RenderTile = *RenderTile32;
78 				break;
79 			default:
80 				return 1;
81 		}
82 	}
83 
84 	if (!bBIOSTextROMEnabled && nBankswitch[nNeoActiveSlot]) {
85 
86 		if (!NeoTextROMCurrent) {
87 			return 0;
88 		}
89 
90 		if (nBankswitch[nNeoActiveSlot] == 1) {
91 
92 			// Garou, Metal Slug 3, Metal Slug 4
93 
94 			INT32 nOffset[32];
95 			INT32 nBank = (3 << 12);
96 			INT32 z = 0;
97 
98 			y = 0;
99 			while (y < 32) {
100 				if (*((UINT16*)(NeoGraphicsRAM + 0xEA00 + z)) == 0x0200 && (*((UINT16*)(NeoGraphicsRAM + 0xEB00 + z)) & 0xFF00) == 0xFF00) {
101 					nBank = ((*((UINT16*)(NeoGraphicsRAM + 0xEB00 + z)) & 3) ^ 3) << 12;
102 					nOffset[y++] = nBank;
103 				}
104 				nOffset[y++] = nBank;
105 				z += 4;
106 			}
107 
108 			for (y = 2, pTileRow += 2; y < 30; y++, pCurrentRow += nTileDown, pTileRow++) {
109 				pTextROM    = NeoTextROMCurrent        + (nOffset[y - 2] << 5);
110 				pTileAttrib = NeoTextTileAttribActive +  nOffset[y - 2];
111 				for (x = nMinX, pTile = pCurrentRow; x < nMaxX; x++, pTile += nTileLeft) {
112 					UINT32 nTile = pTileRow[x << 5];
113 					INT32 nPalette = nTile & 0xF000;
114 					nTile &= 0x0FFF;
115 					nTransparent = (UINT8)pTileAttrib[nTile];
116 					if (nTransparent != 1) {
117 						pTileData = pTextROM + (nTile << 5);
118 						pTilePalette = &pTextPalette[nPalette >> 8];
119 						RenderTile();
120 					}
121 				}
122 			}
123 		} else {
124 
125 			// KOF2000
126 
127 			UINT16* pBankInfo = (UINT16*)(NeoGraphicsRAM + 0xEA00) + 1;
128 			pTextROM    = NeoTextROMCurrent;
129 			pTileAttrib = NeoTextTileAttribActive;
130 
131 			for (y = 2, pTileRow += 2; y < 30; y++, pCurrentRow += nTileDown, pTileRow++, pBankInfo++) {
132  				for (x = nMinX, pTile = pCurrentRow; x < nMaxX; x++, pTile += nTileLeft) {
133 					UINT32 nTile = pTileRow[x << 5];
134 					INT32 nPalette = nTile & 0xF000;
135 					nTile &= 0x0FFF;
136 					nTile += (((pBankInfo[nBankLookupAddress[x]] >> nBankLookupShift[x]) & 3) ^ 3) << 12;
137 					nTransparent = (UINT8)pTileAttrib[nTile];
138 					if (nTransparent != 1) {
139 						pTileData = pTextROM + (nTile << 5);
140 						pTilePalette = &pTextPalette[nPalette >> 8];
141 						RenderTile();
142 					}
143 				}
144 			}
145 		}
146 	} else {
147 		if (bBIOSTextROMEnabled) {
148 			pTextROM    = NeoTextROMBIOS;
149 			pTileAttrib = NeoTextTileAttribBIOS;
150 		} else {
151 			pTextROM    = NeoTextROMCurrent;
152 			pTileAttrib = NeoTextTileAttribActive;
153 		}
154 		if (!pTextROM) {
155 			return 0;
156 		}
157 
158 		for (y = 2, pTileRow += 2; y < 30; y++, pCurrentRow += nTileDown, pTileRow++) {
159 			for (x = nMinX, pTile = pCurrentRow; x < nMaxX; x++, pTile += nTileLeft) {
160 				UINT32 nTile = pTileRow[x << 5];
161 				INT32 nPalette = nTile & 0xF000;
162 				nTile &= 0xFFF;
163 				nTransparent = (UINT8)pTileAttrib[nTile];
164 				if (nTransparent != 1) {
165 					pTileData = pTextROM + (nTile << 5);
166 					pTilePalette = &pTextPalette[nPalette >> 8];
167 					RenderTile();
168 				}
169 			}
170 		}
171 	}
172 
173 	return 0;
174 }
175 
NeoExitText(INT32 nSlot)176 void NeoExitText(INT32 nSlot)
177 {
178 	BurnFree(NeoTextTileAttribBIOS);
179 	BurnFree(NeoTextTileAttrib[nSlot]);
180 	NeoTextTileAttribActive = NULL;
181 }
182 
NeoUpdateTextAttribBIOS(INT32 nOffset,INT32 nSize)183 static void NeoUpdateTextAttribBIOS(INT32 nOffset, INT32 nSize)
184 {
185 	for (INT32 i = nOffset & ~31; i < nOffset + nSize; i += 32) {
186 		NeoTextTileAttribBIOS[i >> 5] = (((INT64*)NeoTextROMBIOS)[(i >> 3) + 0] ||
187 										 ((INT64*)NeoTextROMBIOS)[(i >> 3) + 1] ||
188 										 ((INT64*)NeoTextROMBIOS)[(i >> 3) + 2] ||
189 										 ((INT64*)NeoTextROMBIOS)[(i >> 3) + 3])
190 									  ? 0 : 1;
191 	}
192 }
193 
NeoUpdateTextAttribOne(const INT32 nOffset)194 static inline void NeoUpdateTextAttribOne(const INT32 nOffset)
195 {
196 	NeoTextTileAttribActive[nOffset >> 5] = 1;
197 
198 	for (INT32 i = nOffset; i < nOffset + 32; i += 4) {
199 		if (*((UINT32*)(NeoTextROMCurrent + i))) {
200 			NeoTextTileAttribActive[nOffset >> 5] = 0;
201 			break;
202 		}
203 	}
204 }
205 
NeoUpdateTextAttrib(INT32 nOffset,INT32 nSize)206 static void NeoUpdateTextAttrib(INT32 nOffset, INT32 nSize)
207 {
208 	nOffset &= ~0x1F;
209 
210 	for (INT32 i = nOffset; i < nOffset + nSize; i += 32) {
211 		NeoUpdateTextAttribOne(i);
212 	}
213 }
214 
NeoUpdateTextOne(INT32 nOffset,const UINT8 byteValue)215 void NeoUpdateTextOne(INT32 nOffset, const UINT8 byteValue)
216 {
217 	nOffset = (nOffset & ~0x1F) | (((nOffset ^ 0x10) & 0x18) >> 3) | ((nOffset & 0x07) << 2);
218 
219 	if (byteValue) {
220 		NeoTextTileAttribActive[nOffset >> 5] = 0;
221 	} else {
222 		if (NeoTextTileAttribActive[nOffset >> 5] == 0 && NeoTextROMCurrent[nOffset]) {
223 			NeoTextTileAttribActive[nOffset >> 5] = 1;
224 			NeoUpdateTextAttribOne(nOffset);
225 		}
226 	}
227 
228 	NeoTextROMCurrent[nOffset] = byteValue;
229 }
230 
NeoTextDecodeTile(const UINT8 * pData,UINT8 * pDest)231 static inline void NeoTextDecodeTile(const UINT8* pData, UINT8* pDest)
232 {
233 	UINT8 nBuffer[32];
234 
235 	for (INT32 i = 0; i < 8; i++) {
236 		nBuffer[0 + i * 4] = pData[16 + i];
237 		nBuffer[1 + i * 4] = pData[24 + i];
238 		nBuffer[2 + i * 4] = pData[ 0 + i];
239 		nBuffer[3 + i * 4] = pData[ 8 + i];
240 	}
241 
242 	for (INT32 i = 0; i < 32; i++) {
243 		pDest[i]  = nBuffer[i] << 4;
244 		pDest[i] |= nBuffer[i] >> 4;
245 	}
246 }
247 
NeoDecodeTextBIOS(INT32 nOffset,const INT32 nSize,UINT8 * pData)248 void NeoDecodeTextBIOS(INT32 nOffset, const INT32 nSize, UINT8* pData)
249 {
250 	UINT8* pEnd = pData + nSize;
251 
252 	for (UINT8* pDest = NeoTextROMBIOS + (nOffset & ~0x1F); pData < pEnd; pData += 32, pDest += 32) {
253 		NeoTextDecodeTile(pData, pDest);
254 	}
255 
256 //	if (NeoTextTileAttribBIOS) {
257 //		NeoUpdateTextAttribBIOS(0, nSize);
258 //	}
259 }
260 
NeoDecodeText(INT32 nOffset,const INT32 nSize,UINT8 * pData,UINT8 * pDest)261 void NeoDecodeText(INT32 nOffset, const INT32 nSize, UINT8* pData, UINT8* pDest)
262 {
263 	UINT8* pEnd = pData + nSize;
264 
265 	for (pData += (nOffset & ~0x1F); pData < pEnd; pData += 32, pDest += 32) {
266 		NeoTextDecodeTile(pData, pDest);
267 	}
268 }
269 
NeoUpdateText(INT32 nOffset,const INT32 nSize,UINT8 * pData,UINT8 * pDest)270 void NeoUpdateText(INT32 nOffset, const INT32 nSize, UINT8* pData, UINT8* pDest)
271 {
272 	NeoDecodeText(nOffset, nSize, pData, pDest);
273 	if (NeoTextTileAttribActive) {
274 		NeoUpdateTextAttrib((nOffset & ~0x1F), nSize);
275 	}
276 }
277 
NeoSetTextSlot(INT32 nSlot)278 void NeoSetTextSlot(INT32 nSlot)
279 {
280 	NeoTextROMCurrent       = NeoTextROM[nSlot];
281 	NeoTextTileAttribActive = NeoTextTileAttrib[nSlot];
282 }
283 
NeoTextBlendInit(INT32 nSlot)284 static void NeoTextBlendInit(INT32 nSlot)
285 {
286 	char filename[256];
287 
288 	sprintf (filename, "support/blend/%s.blde", BurnDrvGetTextA(DRV_NAME));
289 
290 	FILE *fa = fopen(filename, "rt");
291 
292 	if (fa == NULL) {
293 		sprintf (filename, "support/blend/%s.blde", BurnDrvGetTextA(DRV_PARENT));
294 
295 		fa = fopen(filename, "rt");
296 
297 		if (fa == NULL) {
298 			return;
299 		}
300 	}
301 
302 	bprintf (PRINT_IMPORTANT, _T("Using text blending (.bld) table!\n"));
303 
304 	char szLine[64];
305 
306 	INT32 table[4] = { 0, 0xff-0x3f, 0xff-0x7f, 0xff-0x7f }; // last one 7f?
307 
308 	while (1)
309 	{
310 		if (fgets (szLine, 64, fa) == NULL) break;
311 
312 		if (strncmp ("Game", szLine, 4) == 0) continue; 	// don't care
313 		if (strncmp ("Name", szLine, 4) == 0) continue; 	// don't care
314 		if (szLine[0] == ';') continue;				// comment (also don't care)
315 
316 		INT32 type;
317 		UINT32 min,max,k, single_entry = (UINT32)-1;
318 
319 		for (k = 0; k < strlen(szLine); k++) {
320 			if (szLine[k] == '-') { single_entry = k+1; break; }
321 		}
322 
323 /*		if (single_entry < 0) {
324 			sscanf(szLine,"%x %d",&max,&type);
325 			min = max;
326 		} else {*/
327 			sscanf(szLine,"%x",&min);
328 			sscanf(szLine+single_entry,"%x %d",&max,&type);
329 //		}
330 
331 		for (k = min; k <= max && k < ((UINT32)nNeoTextROMSize[nSlot]/0x20); k++) {
332 			if (NeoTextTileAttrib[nSlot][k] != 1) 	// ?
333 				NeoTextTileAttrib[nSlot][k] = table[type&3];
334 		}
335 	}
336 
337 	fclose (fa);
338 }
339 
NeoInitText(INT32 nSlot)340 INT32 NeoInitText(INT32 nSlot)
341 {
342 	if (nSlot < 0) {
343 		NeoTextTileAttribBIOS    = (INT8*)BurnMalloc(0x1000);
344 		for (INT32 i = 0; i < 0x1000; i++) {
345 			NeoTextTileAttribBIOS[i] = 1;
346 		}
347 		NeoUpdateTextAttribBIOS(0, 0x020000);
348 
349 		return 0;
350 	}
351 
352 	INT32 nTileNum = nNeoTextROMSize[nSlot] >> 5;
353 
354 //	NeoExitText(nSlot);
355 
356 	NeoTextTileAttrib[nSlot] = (INT8*)BurnMalloc((nTileNum < 0x1000) ? 0x1000 : nTileNum);
357 
358 	if (nNeoScreenWidth == 304) {
359 		nMinX = 1;
360 		nMaxX = 39;
361 	} else {
362 		nMinX = 0;
363 		nMaxX = 40;
364 	}
365 
366 	// Set up tile attributes
367 
368 	NeoTextROMCurrent       = NeoTextROM[nSlot];
369 	NeoTextTileAttribActive = NeoTextTileAttrib[nSlot];
370 	for (INT32 i = 0; i < ((nTileNum < 0x1000) ? 0x1000 : nTileNum); i++) {
371 		NeoTextTileAttribActive[i] = 1;
372 	}
373 	NeoUpdateTextAttrib(0, nNeoTextROMSize[nSlot]);
374 
375 	NeoTextBlendInit(nSlot);
376 
377 	// Set up tile bankswitching
378 
379 	nBankswitch[nSlot] = 0;
380 	if (nNeoTextROMSize[nSlot] > 0x040000) {
381 //		if (BurnDrvGetHardwareCode() & HARDWARE_SNK_CMC50) {
382 		if (BurnDrvGetHardwareCode() & HARDWARE_SNK_ALTERNATE_TEXT) {
383 			nBankswitch[nSlot] = 2;
384 
385 			// Precompute lookup-tables
386 			for (INT32 x = nMinX; x < nMaxX; x++) {
387 				nBankLookupAddress[x] = (x / 6) << 5;
388 				nBankLookupShift[x] = (5 - (x % 6)) << 1;
389 			}
390 
391 		} else {
392 			nBankswitch[nSlot] = 1;
393 		}
394 	}
395 
396 	return 0;
397 }
398