1 // license:LGPL-2.1+
2 // copyright-holders:David Haywood, Angelo Salese, ElSemi, Andrew Gardner
3 
4 /* Hyper NeoGeo 64 Sprite bits */
5 
6 /*
7  * Sprite Format
8  * ------------------
9  *
10  * uint32_t | Bits                                    | Use
11  *        | 3322 2222 2222 1111 1111 11             |
12  * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
13  *   0    | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | x/y position
14  *   1    | YYYY YYYY YYYY YYYY XXXX XXXX XXXX XXXX | x/y zoom (*)
15  *   2    | ---- -zzz zzzz zzzz ---- ---I cccc CCCC | Z-buffer value, 'Inline' chain flag, x/y chain
16  *   3    | ---- ---- pppp pppp ---- ---- ---- ---- | palette entry
17  *   4    | mmmm -?fF a??? tttt tttt tttt tttt tttt | mosaic factor, unknown (**) , flip bits, additive blending, unknown (***), tile number
18  *   5    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
19  *   6    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
20  *   7    | ---- ---- ---- ---- ---- ---- ---- ---- | not used ??
21  *
22  * (*) Fatal Fury WA standard elements are 0x1000-0x1000, all the other games sets 0x100-0x100, related to the bit 27 of sprite regs 0?
23  * (**) setted by black squares in ranking screen in Samurai Shodown 64 1, sprite disable?
24  * (***) bit 22 is setted on some Fatal Fury WA snow (not all of them), bit 21 is setted on Xrally how to play elements in attract mode
25  ** Sprite Global Registers
26  * -----------------------
27  *
28  * uint32_t | Bits                                    | Use
29  *        | 3322 2222 2222 1111 1111 11             |
30  * -------+-1098-7654-3210-9876-5432-1098-7654-3210-+----------------
31  *   0    | ssss z--f b--- -aap ---- ---- ---- ---- | s = unknown, samsho  z = zooming mode, f = depthfilter mode (unset set in roadedge ingame) b = bpp select a = always, p = post, disable?
32  *   1    | yyyy yyyy yyyy yyyy xxxx xxxx xxxx xxxx | global sprite offset (ss64 rankings in attract, roadedge HUD scroll when starting game)
33  *   2    | ---- ---- ---- uuuu uuuu uuuu uuuu uuuu | u = unknown, set to 0x000fffff in roadedge ingame, bbust2, samsho - also possible depthfilter related
34  *   3    | ---- ---- ---- ---- ---- ---- ---- ---- |
35  *   4    | ---- ---- ---- ---- ---- ---- ---- ---- |
36  * (anything else is unknown at the current time)
37  * Notes:
38  * [4]
39  * 0x0e0 in Samurai Shodown/Xrally games, 0x1c0 in all the others, zooming factor?
40 
41  */
42 
draw_sprites(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)43 void hng64_state::draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
44 {
45 	gfx_element *gfx;
46 	uint32_t *source = m_spriteram;
47 	uint32_t *finish = m_spriteram + 0xc000/4;
48 
49 	// global offsets in sprite regs
50 	int spriteoffsx = (m_spriteregs[1]>>0)&0xffff;
51 	int spriteoffsy = (m_spriteregs[1]>>16)&0xffff;
52 
53 #if 0
54 	for (int iii = 0; iii < 0x0f; iii++)
55 		osd_printf_debug("%.8x ", m_videoregs[iii]);
56 	osd_printf_debug("\n");
57 #endif
58 
59 	while( source<finish )
60 	{
61 		int tileno,chainx,chainy,xflip;
62 		int pal,xinc,yinc,yflip;
63 		uint16_t xpos, ypos;
64 		int xdrw,ydrw;
65 		int chaini;
66 		int zbuf;
67 		uint32_t zoomx,zoomy;
68 		float foomX, foomY;
69 		int blend;
70 		int disable;
71 
72 
73 		ypos = (source[0]&0xffff0000)>>16;
74 		xpos = (source[0]&0x0000ffff)>>0;
75 		xpos += (spriteoffsx);
76 		ypos += (spriteoffsy);
77 
78 		tileno= (source[4]&0x0007ffff);
79 		blend=  (source[4]&0x00800000);
80 		yflip=  (source[4]&0x01000000)>>24;
81 		xflip=  (source[4]&0x02000000)>>25;
82 		disable=(source[4]&0x04000000)>>26; // ss64 rankings?
83 
84 		pal =(source[3]&0x00ff0000)>>16;
85 
86 		chainy=(source[2]&0x0000000f);
87 		chainx=(source[2]&0x000000f0)>>4;
88 		chaini=(source[2]&0x00000100);
89 		zbuf = (source[2]&0x07ff0000)>>16; //?
90 
91 		zoomy = (source[1]&0xffff0000)>>16;
92 		zoomx = (source[1]&0x0000ffff)>>0;
93 
94 		int filtervalue = 0x000;
95 
96 		// This flips between ingame and other screens for roadedge, where the sprites which are filtered definitely needs to change and the game explicitly swaps the values in the sprite list at the same time.
97 		// m_spriteregs[2] could also play a part as it also flips between 0x00000000 and 0x000fffff at the same time
98 		// Samsho games also set the upper 3 bits which could be related, samsho games still have some unwanted sprites (but also use the other 'sprite clear' mechanism)
99 		// Could also be draw order related, check if it inverts the z value?
100 		if (m_spriteregs[0] & 0x01000000)
101 			filtervalue = 0x7ff;
102 
103 		if(zbuf == filtervalue)
104 		{
105 			source+=8;
106 			continue;
107 		}
108 
109 		if(disable)
110 		{
111 			source+=8;
112 			continue;
113 		}
114 
115 #if 0
116 		if (!(source[4] == 0x00000000 || source[4] == 0x000000aa))
117 			osd_printf_debug("unknown : %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x \n", source[0], source[1], source[2], source[3],
118 				source[4], source[5], source[6], source[7]);
119 #endif
120 
121 		/* Calculate the zoom */
122 		{
123 			int zoom_factor;
124 
125 			/* FIXME: regular zoom mode has precision bugs, can be easily seen in Samurai Shodown 64 intro */
126 			zoom_factor = (m_spriteregs[0] & 0x08000000) ? 0x1000 : 0x100;
127 			if(!zoomx) zoomx=zoom_factor;
128 			if(!zoomy) zoomy=zoom_factor;
129 
130 			/* First, prevent any possible divide by zero errors */
131 			foomX = (float)(zoom_factor) / (float)zoomx;
132 			foomY = (float)(zoom_factor) / (float)zoomy;
133 
134 			zoomx = ((int)foomX) << 16;
135 			zoomy = ((int)foomY) << 16;
136 
137 			zoomx += (int)((foomX - floor(foomX)) * (float)0x10000);
138 			zoomy += (int)((foomY - floor(foomY)) * (float)0x10000);
139 		}
140 
141 		if (m_spriteregs[0] & 0x00800000) //bpp switch
142 		{
143 			gfx= m_gfxdecode->gfx(4);
144 		}
145 		else
146 		{
147 			gfx= m_gfxdecode->gfx(5);
148 			tileno>>=1;
149 			pal&=0xf;
150 		}
151 
152 		// Accommodate for chaining and flipping
153 		if(xflip)
154 		{
155 			xinc=-(int)(16.0f*foomX);
156 			xpos-=xinc*chainx;
157 		}
158 		else
159 		{
160 			xinc=(int)(16.0f*foomX);
161 		}
162 
163 		if(yflip)
164 		{
165 			yinc=-(int)(16.0f*foomY);
166 			ypos-=yinc*chainy;
167 		}
168 		else
169 		{
170 			yinc=(int)(16.0f*foomY);
171 		}
172 
173 #if 0
174 		if (((source[2) & 0xffff0000) >> 16) == 0x0001)
175 		{
176 			popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]);
177 			//popmessage("T %.8x %.8x %.8x %.8x %.8x", source[0], source[1], source[2], source[3], source[4]);
178 		}
179 #endif
180 
181 		for(ydrw=0;ydrw<=chainy;ydrw++)
182 		{
183 			for(xdrw=0;xdrw<=chainx;xdrw++)
184 			{
185 				int16_t drawx = xpos+(xinc*xdrw);
186 				int16_t drawy = ypos+(yinc*ydrw);
187 
188 				// 0x3ff (0x200 sign bit) based on sams64_2 char select
189 				drawx &= 0x3ff;
190 				drawy &= 0x3ff;
191 
192 				if (drawx&0x0200)drawx-=0x400;
193 				if (drawy&0x0200)drawy-=0x400;
194 
195 				if (!chaini)
196 				{
197 					if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
198 					else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
199 					tileno++;
200 				}
201 				else // inline chain mode, used by ss64
202 				{
203 					tileno=(source[4]&0x0007ffff);
204 					pal =(source[3]&0x00ff0000)>>16;
205 
206 					if (m_spriteregs[0] & 0x00800000) //bpp switch
207 					{
208 						gfx= m_gfxdecode->gfx(4);
209 					}
210 					else
211 					{
212 						gfx= m_gfxdecode->gfx(5);
213 						tileno>>=1;
214 						pal&=0xf;
215 					}
216 
217 					if (!blend) gfx->prio_zoom_transpen(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
218 					else gfx->prio_zoom_transpen_additive(bitmap,cliprect,tileno,pal,xflip,yflip,drawx,drawy,zoomx,zoomy/*0x10000*/,screen.priority(), 0,0);
219 					source +=8;
220 				}
221 
222 			}
223 		}
224 
225 		if (!chaini) source +=8;
226 	}
227 }
228