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