1 // license:BSD-3-Clause
2 // copyright-holders:Phil Stroffolino, David Haywood
3 
4 #include "emu.h"
5 #include "namcos21_3d.h"
6 
7 DEFINE_DEVICE_TYPE(NAMCOS21_3D, namcos21_3d_device, "namcos21_3d", "Namco System 21 3D Rasterizer")
8 
namcos21_3d_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)9 namcos21_3d_device::namcos21_3d_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
10 	device_t(mconfig, NAMCOS21_3D, tag, owner, clock),
11 	m_fixed_palbase(-1),
12 	m_zz_shift(10),
13 	m_zzmult(0x100),
14 	m_depth_reverse(false),
15 	m_poly_frame_width(0),
16 	m_poly_frame_height(0),
17 	m_framebuffer_size_in_bytes(0)
18 {
19 }
20 
device_start()21 void namcos21_3d_device::device_start()
22 {
23 	allocate_poly_framebuffer();
24 }
25 
device_reset()26 void namcos21_3d_device::device_reset()
27 {
28 }
29 
allocate_poly_framebuffer()30 void namcos21_3d_device::allocate_poly_framebuffer()
31 {
32 	if (m_framebuffer_size_in_bytes == 0)
33 		fatalerror("m_framebuffer_size_in_bytes == 0\n");
34 
35 	m_mpPolyFrameBufferZ = std::make_unique<uint16_t[]>(m_framebuffer_size_in_bytes / 2);
36 	m_mpPolyFrameBufferPens = std::make_unique<uint16_t[]>(m_framebuffer_size_in_bytes / 2);
37 
38 	m_mpPolyFrameBufferZ2 = std::make_unique<uint16_t[]>(m_framebuffer_size_in_bytes / 2);
39 	m_mpPolyFrameBufferPens2 = std::make_unique<uint16_t[]>(m_framebuffer_size_in_bytes / 2);
40 
41 	swap_and_clear_poly_framebuffer();
42 	swap_and_clear_poly_framebuffer();
43 }
44 
swap_and_clear_poly_framebuffer()45 void namcos21_3d_device::swap_and_clear_poly_framebuffer()
46 {
47 	/* swap work and visible framebuffers */
48 	m_mpPolyFrameBufferZ.swap(m_mpPolyFrameBufferZ2);
49 
50 	m_mpPolyFrameBufferPens.swap(m_mpPolyFrameBufferPens2);
51 
52 	/* wipe work zbuffer */
53 	for (int i = 0; i < m_poly_frame_width*m_poly_frame_height; i++)
54 	{
55 		m_mpPolyFrameBufferZ[i] = 0x7fff;
56 	}
57 }
58 
copy_visible_poly_framebuffer(bitmap_ind16 & bitmap,const rectangle & clip,int zlo,int zhi)59 void namcos21_3d_device::copy_visible_poly_framebuffer(bitmap_ind16 &bitmap, const rectangle &clip, int zlo, int zhi)
60 {
61 	/* blit the visible framebuffer */
62 	for (int sy = clip.top(); sy <= clip.bottom(); sy++)
63 	{
64 		uint16_t *const dest = &bitmap.pix(sy);
65 		uint16_t const *const pPen = m_mpPolyFrameBufferPens2.get() + m_poly_frame_width * sy;
66 		uint16_t const *const pZ = m_mpPolyFrameBufferZ2.get() + m_poly_frame_width * sy;
67 		for (int sx = clip.left(); sx <= clip.right(); sx++)
68 		{
69 			int z = pZ[sx];
70 			//if( pZ[sx]!=0x7fff )
71 			if (z >= zlo && z <= zhi)
72 			{
73 				dest[sx] = pPen[sx];
74 			}
75 		}
76 	}
77 }
78 
79 /*********************************************************************************************/
80 
81 #define SWAP(T,A,B) { const T *temp = A; A = B; B = temp; }
82 
renderscanline_flat(const edge * e1,const edge * e2,int sy,unsigned color,int depthcueenable)83 void namcos21_3d_device::renderscanline_flat(const edge *e1, const edge *e2, int sy, unsigned color, int depthcueenable)
84 {
85 	if (e1->x > e2->x)
86 	{
87 		SWAP(edge, e1, e2);
88 	}
89 
90 	{
91 		uint16_t *pDest = m_mpPolyFrameBufferPens.get() + sy * m_poly_frame_width;
92 		uint16_t *pZBuf = m_mpPolyFrameBufferZ.get() + sy * m_poly_frame_width;
93 		int x0 = (int)e1->x;
94 		int x1 = (int)e2->x;
95 		int w = x1 - x0;
96 		if (w)
97 		{
98 			double z = e1->z;
99 			double dz = (e2->z - e1->z) / w;
100 			int x, crop;
101 			crop = -x0;
102 			if (crop > 0)
103 			{
104 				z += crop * dz;
105 				x0 = 0;
106 			}
107 			if (x1 > m_poly_frame_width - 1)
108 			{
109 				x1 = m_poly_frame_width - 1;
110 			}
111 
112 			for (x = x0; x < x1; x++)
113 			{
114 				uint16_t zz = (uint16_t)z;
115 				if (zz < pZBuf[x])
116 				{
117 					int pen = color;
118 					if (depthcueenable && zz > 0)
119 					{
120 						int depth = 0;
121 						if (m_depth_reverse)
122 						{
123 							depth = (zz >> m_zz_shift)*m_zzmult;
124 							pen += depth;
125 						}
126 						else
127 						{
128 							depth = (zz >> m_zz_shift)*m_zzmult;
129 							pen -= depth;
130 						}
131 					}
132 					pDest[x] = pen;
133 					pZBuf[x] = zz;
134 				}
135 				z += dz;
136 			}
137 		}
138 	}
139 }
140 
rendertri(const n21_vertex * v0,const n21_vertex * v1,const n21_vertex * v2,unsigned color,int depthcueenable)141 void namcos21_3d_device::rendertri(const n21_vertex *v0, const n21_vertex *v1, const n21_vertex *v2, unsigned color, int depthcueenable)
142 {
143 	int dy, ystart, yend, crop;
144 
145 	/* first, sort so that v0->y <= v1->y <= v2->y */
146 	for (;;)
147 	{
148 		if (v0->y > v1->y)
149 		{
150 			SWAP(n21_vertex, v0, v1);
151 		}
152 		else if (v1->y > v2->y)
153 		{
154 			SWAP(n21_vertex, v1, v2);
155 		}
156 		else
157 		{
158 			break;
159 		}
160 	}
161 
162 	ystart = v0->y;
163 	yend = v2->y;
164 	dy = yend - ystart;
165 	if (dy)
166 	{
167 		int y;
168 		edge e1; /* short edge (top and bottom) */
169 		edge e2; /* long (common) edge */
170 
171 		double dx2dy = (v2->x - v0->x) / dy;
172 		double dz2dy = (v2->z - v0->z) / dy;
173 
174 		double dx1dy;
175 		double dz1dy;
176 
177 		e2.x = v0->x;
178 		e2.z = v0->z;
179 		crop = -ystart;
180 		if (crop > 0)
181 		{
182 			e2.x += dx2dy * crop;
183 			e2.z += dz2dy * crop;
184 		}
185 
186 		ystart = v0->y;
187 		yend = v1->y;
188 		dy = yend - ystart;
189 		if (dy)
190 		{
191 			e1.x = v0->x;
192 			e1.z = v0->z;
193 
194 			dx1dy = (v1->x - v0->x) / dy;
195 			dz1dy = (v1->z - v0->z) / dy;
196 
197 			crop = -ystart;
198 			if (crop > 0)
199 			{
200 				e1.x += dx1dy * crop;
201 				e1.z += dz1dy * crop;
202 				ystart = 0;
203 			}
204 			if (yend > m_poly_frame_height - 1) yend = m_poly_frame_height - 1;
205 
206 			for (y = ystart; y < yend; y++)
207 			{
208 				renderscanline_flat(&e1, &e2, y, color, depthcueenable);
209 
210 				e2.x += dx2dy;
211 				e2.z += dz2dy;
212 
213 				e1.x += dx1dy;
214 				e1.z += dz1dy;
215 			}
216 		}
217 
218 		ystart = v1->y;
219 		yend = v2->y;
220 		dy = yend - ystart;
221 		if (dy)
222 		{
223 			e1.x = v1->x;
224 			e1.z = v1->z;
225 
226 			dx1dy = (v2->x - v1->x) / dy;
227 			dz1dy = (v2->z - v1->z) / dy;
228 
229 			crop = -ystart;
230 			if (crop > 0)
231 			{
232 				e1.x += dx1dy * crop;
233 				e1.z += dz1dy * crop;
234 				ystart = 0;
235 			}
236 			if (yend > m_poly_frame_height - 1)
237 			{
238 				yend = m_poly_frame_height - 1;
239 			}
240 			for (y = ystart; y < yend; y++)
241 			{
242 				renderscanline_flat(&e1, &e2, y, color, depthcueenable);
243 
244 				e2.x += dx2dy;
245 				e2.z += dz2dy;
246 
247 				e1.x += dx1dy;
248 				e1.z += dz1dy;
249 			}
250 		}
251 	}
252 }
253 
draw_quad(int sx[4],int sy[4],int zcode[4],int color)254 void namcos21_3d_device::draw_quad(int sx[4], int sy[4], int zcode[4], int color)
255 {
256 	n21_vertex a, b, c, d;
257 	int depthcueenable = 1;
258 	/*
259 	    0x0000..0x1fff  sprite palettes (0x20 sets of 0x100 colors)
260 	    0x2000..0x3fff  polygon palette bank0 (0x10 sets of 0x200 colors or 0x20 sets of 0x100 colors)
261 	    0x4000..0x5fff  polygon palette bank1 (0x10 sets of 0x200 colors or 0x20 sets of 0x100 colors)
262 	    0x6000..0x7fff  polygon palette bank2 (0x10 sets of 0x200 colors or 0x20 sets of 0x100 colors)
263 	*/
264 
265 
266 	if (m_fixed_palbase != -1)
267 	{
268 		// Winning Run & Driver's Eyes use this logic
269 		color = m_fixed_palbase | (color & 0xff);
270 	}
271 	else
272 	{ /* map color code to hardware pen */
273 		int code = color >> 8;
274 		if (code & 0x80)
275 		{
276 			color = color & 0xff;
277 			// color = 0x3e00|color;
278 			color = 0x2100 | color;
279 			depthcueenable = 0;
280 		}
281 		else
282 		{
283 			color &= 0xff;
284 			color = 0x3e00 | color;
285 			if ((code & 0x02) == 0)
286 			{
287 				color |= 0x100;
288 			}
289 		}
290 	}
291 	a.x = sx[0];
292 	a.y = sy[0];
293 	a.z = zcode[0];
294 
295 	b.x = sx[1];
296 	b.y = sy[1];
297 	b.z = zcode[1];
298 
299 	c.x = sx[2];
300 	c.y = sy[2];
301 	c.z = zcode[2];
302 
303 	d.x = sx[3];
304 	d.y = sy[3];
305 	d.z = zcode[3];
306 
307 	rendertri(&a, &b, &c, color, depthcueenable);
308 	rendertri(&c, &d, &a, color, depthcueenable);
309 }
310