1 // license:BSD-3-Clause
2 // copyright-holders:R. Belmont, Ville Linde
3 #include "emu.h"
4 #include "video/rgbutil.h"
5 #include "includes/model3.h"
6
7 /*
8 TODO:
9 - Tilemap flash effect
10 - Fog
11 - Mipmapping
12 - Mipmap uploads smaller than a tile
13 - Some of the 4-bit and 8-bit textures need their alpha values rechecked
14 - Spotlights
15 - Recheck normal vector transform
16
17 */
18
19 #define ENABLE_BILINEAR 1
20
21 #define TRI_PARAM_TEXTURE_PAGE 0x1
22 #define TRI_PARAM_TEXTURE_MIRROR_U 0x2
23 #define TRI_PARAM_TEXTURE_MIRROR_V 0x4
24 #define TRI_PARAM_TEXTURE_ENABLE 0x8
25 #define TRI_PARAM_ALPHA_TEST 0x10
26 #define TRI_PARAM_COLOR_MOD 0x20
27
28 #define TRI_BUFFER_SIZE 50000
29 #define TRI_ALPHA_BUFFER_SIZE 15000
30
31 struct model3_polydata
32 {
33 cached_texture *texture;
34 uint32_t color;
35 uint32_t texture_param;
36 int transparency;
37 int intensity;
38 };
39
40 class model3_renderer : public poly_manager<float, model3_polydata, 6, 50000>
41 {
42 public:
model3_renderer(model3_state & state,int width,int height)43 model3_renderer(model3_state &state, int width, int height)
44 : poly_manager<float, model3_polydata, 6, 50000>(state.machine())
45 {
46 m_fb = std::make_unique<bitmap_rgb32>(width, height);
47 m_zb = std::make_unique<bitmap_ind32>(width, height);
48 }
49
50 void draw(bitmap_rgb32 &bitmap, const rectangle &cliprect);
51 void draw_opaque_triangles(const m3_triangle* tris, int num_tris);
52 void draw_alpha_triangles(const m3_triangle* tris, int num_tris);
53 void clear_fb();
54 void clear_zb();
55 void draw_scanline_solid(int32_t scanline, const extent_t &extent, const model3_polydata &extradata, int threadid);
56 void draw_scanline_solid_trans(int32_t scanline, const extent_t &extent, const model3_polydata &extradata, int threadid);
57 void draw_scanline_tex(int32_t scanline, const extent_t &extent, const model3_polydata &extradata, int threadid);
58 void draw_scanline_tex_colormod(int32_t scanline, const extent_t &extent, const model3_polydata &extradata, int threadid);
59 void draw_scanline_tex_contour(int32_t scanline, const extent_t &extent, const model3_polydata &extradata, int threadid);
60 void draw_scanline_tex_trans(int32_t scanline, const extent_t &extent, const model3_polydata &extradata, int threadid);
61 void draw_scanline_tex_alpha(int32_t scanline, const extent_t &extent, const model3_polydata &extradata, int threadid);
62 void wait_for_polys();
63
64 private:
65 std::unique_ptr<bitmap_rgb32> m_fb;
66 std::unique_ptr<bitmap_ind32> m_zb;
67 };
68
69
70
71 /*****************************************************************************/
72
73 /* matrix stack */
74 #define MATRIX_STACK_SIZE 256
75
76
77 #define BYTE_REVERSE32(x) (((x >> 24) & 0xff) | \
78 ((x >> 8) & 0xff00) | \
79 ((x << 8) & 0xff0000) | \
80 ((x << 24) & 0xff000000))
81
82 #define BYTE_REVERSE16(x) (((x >> 8) & 0xff) | ((x << 8) & 0xff00))
83
84
model3_exit()85 void model3_state::model3_exit()
86 {
87 #if 0
88 FILE* file;
89 int i;
90 file = fopen("m3_texture_ram.bin","wb");
91 for (i=0; i < 0x200000; i++)
92 {
93 fputc((uint8_t)(m_texture_ram[0][i] >> 8), file);
94 fputc((uint8_t)(m_texture_ram[0][i] >> 0), file);
95 }
96 for (i=0; i < 0x200000; i++)
97 {
98 fputc((uint8_t)(m_texture_ram[1][i] >> 8), file);
99 fputc((uint8_t)(m_texture_ram[1][i] >> 0), file);
100 }
101 fclose(file);
102
103 file = fopen("m3_displist.bin","wb");
104 for (i=0; i < 0x40000; i++)
105 {
106 fputc((uint8_t)(m_display_list_ram[i] >> 24), file);
107 fputc((uint8_t)(m_display_list_ram[i] >> 16), file);
108 fputc((uint8_t)(m_display_list_ram[i] >> 8), file);
109 fputc((uint8_t)(m_display_list_ram[i] >> 0), file);
110 }
111 fclose(file);
112
113 file = fopen("m3_culling_ram.bin","wb");
114 for (i=0; i < 0x100000; i++)
115 {
116 fputc((uint8_t)(m_culling_ram[i] >> 24), file);
117 fputc((uint8_t)(m_culling_ram[i] >> 16), file);
118 fputc((uint8_t)(m_culling_ram[i] >> 8), file);
119 fputc((uint8_t)(m_culling_ram[i] >> 0), file);
120 }
121 fclose(file);
122
123 file = fopen("m3_polygon_ram.bin","wb");
124 for (i=0; i < 0x100000; i++)
125 {
126 fputc((uint8_t)(m_polygon_ram[i] >> 24), file);
127 fputc((uint8_t)(m_polygon_ram[i] >> 16), file);
128 fputc((uint8_t)(m_polygon_ram[i] >> 8), file);
129 fputc((uint8_t)(m_polygon_ram[i] >> 0), file);
130 }
131 fclose(file);
132
133 file = fopen("m3_vrom.bin","wb");
134 for (i=0; i < 0x1000000; i++)
135 {
136 fputc((uint8_t)(m_vrom[i] >> 24), file);
137 fputc((uint8_t)(m_vrom[i] >> 16), file);
138 fputc((uint8_t)(m_vrom[i] >> 8), file);
139 fputc((uint8_t)(m_vrom[i] >> 0), file);
140 }
141 fclose(file);
142 #endif
143
144 // invalidate_texture(0, 0, 0, 6, 5);
145 // invalidate_texture(1, 0, 0, 6, 5);
146 }
147
video_start()148 void model3_state::video_start()
149 {
150 static const gfx_layout char4_layout =
151 {
152 8, 8,
153 31744,
154 4,
155 { 0,1,2,3 },
156 { 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4 },
157 { 1*32, 0*32, 3*32, 2*32, 5*32, 4*32, 7*32, 6*32 },
158 4 * 8*8
159 };
160
161 static const gfx_layout char8_layout =
162 {
163 8, 8,
164 15872,
165 8,
166 { 0,1,2,3,4,5,6,7 },
167 { 4*8, 5*8, 6*8, 7*8, 0*8, 1*8, 2*8, 3*8 },
168 { 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64 },
169 8 * 8*8
170 };
171
172 int width = m_screen->width();
173 int height = m_screen->height();
174
175 m_renderer = auto_alloc(machine(), model3_renderer(*this, width, height));
176
177 m_tri_buffer = auto_alloc_array_clear(machine(), m3_triangle, TRI_BUFFER_SIZE);
178 m_tri_alpha_buffer = auto_alloc_array_clear(machine(), m3_triangle, TRI_ALPHA_BUFFER_SIZE);
179
180 machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&model3_state::model3_exit, this));
181
182 m_m3_char_ram = make_unique_clear<uint64_t[]>(0x100000/8);
183 m_m3_tile_ram = make_unique_clear<uint64_t[]>(0x8000/8);
184
185 m_texture_fifo = make_unique_clear<uint32_t[]>(0x100000/4);
186
187 /* 2x 4MB texture sheets */
188 m_texture_ram[0] = std::make_unique<uint16_t[]>(0x400000/2);
189 m_texture_ram[1] = std::make_unique<uint16_t[]>(0x400000/2);
190
191 /* 1MB Display List RAM */
192 m_display_list_ram = make_unique_clear<uint32_t[]>(0x100000/4);
193 /* 4MB for nodes (< Step 2.0 have only 2MB) */
194 m_culling_ram = make_unique_clear<uint32_t[]>(0x400000/4);
195 /* 4MB Polygon RAM */
196 m_polygon_ram = make_unique_clear<uint32_t[]>(0x400000/4);
197
198 m_vid_reg0 = 0;
199
200 m_layer4[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer0_4bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
201 m_layer8[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer0_8bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
202 m_layer4[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer1_4bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
203 m_layer8[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer1_8bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
204 m_layer4[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer2_4bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
205 m_layer8[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer2_8bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
206 m_layer4[3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer3_4bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
207 m_layer8[3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(model3_state::tile_info_layer3_8bit)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
208
209 // 4-bit tiles
210 m_gfxdecode->set_gfx(0, std::make_unique<gfx_element>(m_palette, char4_layout, (uint8_t*)m_m3_char_ram.get(), 0, m_palette->entries() / 16, 0));
211
212 // 8-bit tiles
213 m_gfxdecode->set_gfx(1, std::make_unique<gfx_element>(m_palette, char8_layout, (uint8_t*)m_m3_char_ram.get(), 0, m_palette->entries() / 256, 0));
214
215 init_matrix_stack();
216 }
217
218 #define MODEL3_TILE_INFO4(address) \
219 do { \
220 uint16_t *tiles = (uint16_t*)&m_m3_tile_ram[address + (tile_index / 4)]; \
221 uint16_t t = BYTE_REVERSE16(tiles[(tile_index & 3) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0)]); \
222 int tile = ((t << 1) & 0x7ffe) | ((t >> 15) & 0x1); \
223 int color = (t & 0x7ff0) >> 4; \
224 tileinfo.set(0, tile, color, 0); \
225 } while (0)
226
227 #define MODEL3_TILE_INFO8(address) \
228 do { \
229 uint16_t *tiles = (uint16_t*)&m_m3_tile_ram[address + (tile_index / 4)]; \
230 uint16_t t = BYTE_REVERSE16(tiles[(tile_index & 3) ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0)]); \
231 int tile = ((t << 1) & 0x7ffe) | ((t >> 15) & 0x1); \
232 int color = (t & 0x7f00) >> 8; \
233 tileinfo.set(1, tile >> 1, color, 0); \
234 } while (0)
235
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer0_4bit)236 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer0_4bit) { MODEL3_TILE_INFO4(0x000); }
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer0_8bit)237 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer0_8bit) { MODEL3_TILE_INFO8(0x000); }
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer1_4bit)238 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer1_4bit) { MODEL3_TILE_INFO4(0x400); }
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer1_8bit)239 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer1_8bit) { MODEL3_TILE_INFO8(0x400); }
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer2_4bit)240 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer2_4bit) { MODEL3_TILE_INFO4(0x800); }
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer2_8bit)241 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer2_8bit) { MODEL3_TILE_INFO8(0x800); }
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer3_4bit)242 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer3_4bit) { MODEL3_TILE_INFO4(0xc00); }
TILE_GET_INFO_MEMBER(model3_state::tile_info_layer3_8bit)243 TILE_GET_INFO_MEMBER(model3_state::tile_info_layer3_8bit) { MODEL3_TILE_INFO8(0xc00); }
244
245 #ifdef UNUSED_FUNCTION
draw_texture_sheet(bitmap_ind16 & bitmap,const rectangle & cliprect)246 void model3_state::draw_texture_sheet(bitmap_ind16 &bitmap, const rectangle &cliprect)
247 {
248 for(int y = cliprect.min_y; y <= cliprect.max_y; y++)
249 {
250 uint16_t *const d = &bitmap.pix(y);
251 int index = (y*2)*2048;
252 for(int x = cliprect.min_x; x <= cliprect.max_x; x++) {
253 uint16_t pix = m_texture_ram[0][index];
254 index+=4;
255 if(pix != 0) {
256 d[x] = pix;
257 }
258 }
259 }
260 }
261 #endif
262
draw_layer(bitmap_rgb32 & bitmap,const rectangle & cliprect,int layer,int sx,int sy,int prio)263 void model3_state::draw_layer(bitmap_rgb32 &bitmap, const rectangle &cliprect, int layer, int sx, int sy, int prio)
264 {
265 int bitdepth = (m_layer_priority & (0x10 << layer)) ? 1 : 0;
266 // int layer_prio = (m_layer_priority & (0x1 << layer)) ? 1 : 0;
267
268 tilemap_t *tmap = bitdepth ? m_layer4[layer] : m_layer8[layer];
269 bitmap_ind16 &pixmap = tmap->pixmap();
270 const pen_t *pens = m_palette->pens();
271
272 uint32_t* palram = (uint32_t*)&m_paletteram64[0];
273 uint16_t* rowscroll_ram = (uint16_t*)&m_m3_char_ram[0x1ec00];
274 uint32_t* rowmask_ram = (uint32_t*)&m_m3_char_ram[0x1ee00];
275
276 int x1 = cliprect.min_x;
277 int y1 = cliprect.min_y;
278 int x2 = cliprect.max_x;
279 int y2 = cliprect.max_y;
280
281 int ix = sx;
282 int iy = sy;
283 if (ix < 0)
284 {
285 ix = 0 - ix;
286 }
287 if (iy < 0)
288 {
289 iy = 0 - iy;
290 }
291
292 for (int y = y1; y <= y2; y++)
293 {
294 uint32_t *const dst = &bitmap.pix(y);
295 uint16_t const *const src = &pixmap.pix(iy & 0x1ff);
296
297 int rowscroll = BYTE_REVERSE16(rowscroll_ram[((layer * 0x200) + y) ^ NATIVE_ENDIAN_VALUE_LE_BE(3,0)]) & 0x7fff;
298 if (rowscroll & 0x100)
299 rowscroll |= ~0x1ff;
300
301 uint16_t rowmask;
302 if (prio && (layer == 1 || layer == 2))
303 rowmask = BYTE_REVERSE32(rowmask_ram[(y & 0x1ff) ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0)]) & 0xffff;
304 else
305 rowmask = 0xffff;
306
307 int iix = ix & 0x1ff;
308
309 int rx1 = x1 - (rowscroll * 2);
310 int rx2 = x2 - (rowscroll * 2);
311
312 if (rx1 < 0)
313 {
314 iix += (0 - rx1);
315 rx1 = 0;
316 }
317 if (rx2 > cliprect.max_x)
318 rx2 = cliprect.max_x;
319
320 for (int x = rx1; x <= rx2; x++)
321 {
322 uint32_t mask = rowmask & (1 << ((iix & 0x1ff) >> 5));
323
324 if (mask)
325 {
326 uint16_t p0 = src[iix & 0x1ff];
327 if ((palram[p0^NATIVE_ENDIAN_VALUE_LE_BE(1,0)] & NATIVE_ENDIAN_VALUE_LE_BE(0x00800000,0x00008000)) == 0)
328 {
329 dst[x] = pens[p0];
330 }
331 }
332 iix++;
333 }
334
335 iy++;
336 }
337 }
338
screen_update_model3(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)339 uint32_t model3_state::screen_update_model3(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
340 {
341 int layer_scroll_x[4], layer_scroll_y[4];
342 uint32_t layer_data[4];
343
344 layer_data[0] = BYTE_REVERSE32((uint32_t)(m_layer_scroll[0] >> 32));
345 layer_data[1] = BYTE_REVERSE32((uint32_t)(m_layer_scroll[0] >> 0));
346 layer_data[2] = BYTE_REVERSE32((uint32_t)(m_layer_scroll[1] >> 32));
347 layer_data[3] = BYTE_REVERSE32((uint32_t)(m_layer_scroll[1] >> 0));
348 layer_scroll_x[0] = layer_data[0] & 0x1ff;
349 layer_scroll_y[0] = (layer_data[0] >> 16) & 0x1ff;
350 layer_scroll_x[1] = layer_data[1] & 0x1ff;
351 layer_scroll_y[1] = (layer_data[1] >> 16) & 0x1ff;
352 layer_scroll_x[2] = layer_data[2] & 0x1ff;
353 layer_scroll_y[2] = (layer_data[2] >> 16) & 0x1ff;
354 layer_scroll_x[3] = layer_data[3] & 0x1ff;
355 layer_scroll_y[3] = (layer_data[3] >> 16) & 0x1ff;
356
357 m_screen_clip = (rectangle*)&cliprect;
358 m_clip3d = cliprect;
359
360 bitmap.fill(0, cliprect);
361
362 // render enabled layers with priority 0
363 if ((layer_data[3] & 0x80000000) && (m_layer_priority & 0x8) == 0)
364 draw_layer(bitmap, cliprect, 3, layer_scroll_x[3], layer_scroll_y[3], 0);
365 if ((layer_data[2] & 0x80000000) && (m_layer_priority & 0x4) == 0)
366 draw_layer(bitmap, cliprect, 2, layer_scroll_x[2], layer_scroll_y[2], 0);
367 if ((layer_data[1] & 0x80000000) && (m_layer_priority & 0x2) == 0)
368 draw_layer(bitmap, cliprect, 1, layer_scroll_x[1], layer_scroll_y[1], 0);
369 if ((layer_data[0] & 0x80000000) && (m_layer_priority & 0x1) == 0)
370 draw_layer(bitmap, cliprect, 0, layer_scroll_x[0], layer_scroll_y[0], 0);
371
372 // render 3D
373 m_renderer->draw(bitmap, cliprect);
374
375 // render enabled layers with priority 1
376 if ((layer_data[3] & 0x80000000) && (m_layer_priority & 0x8) != 0)
377 draw_layer(bitmap, cliprect, 3, layer_scroll_x[3], layer_scroll_y[3], 1);
378 if ((layer_data[2] & 0x80000000) && (m_layer_priority & 0x4) != 0)
379 draw_layer(bitmap, cliprect, 2, layer_scroll_x[2], layer_scroll_y[2], 1);
380 if ((layer_data[0] & 0x80000000) && (m_layer_priority & 0x1) != 0)
381 draw_layer(bitmap, cliprect, 0, layer_scroll_x[0], layer_scroll_y[0], 1);
382 if ((layer_data[1] & 0x80000000) && (m_layer_priority & 0x2) != 0)
383 draw_layer(bitmap, cliprect, 1, layer_scroll_x[1], layer_scroll_y[1], 1);
384
385 return 0;
386 }
387
388
389
model3_char_r(offs_t offset)390 uint64_t model3_state::model3_char_r(offs_t offset)
391 {
392 return m_m3_char_ram[offset];
393 }
394
model3_char_w(offs_t offset,uint64_t data,uint64_t mem_mask)395 void model3_state::model3_char_w(offs_t offset, uint64_t data, uint64_t mem_mask)
396 {
397 COMBINE_DATA(&m_m3_char_ram[offset]);
398 m_gfxdecode->gfx(0)->mark_dirty(offset / 4);
399 m_gfxdecode->gfx(1)->mark_dirty(offset / 8);
400 }
401
model3_tile_r(offs_t offset)402 uint64_t model3_state::model3_tile_r(offs_t offset)
403 {
404 return m_m3_tile_ram[offset];
405 }
406
model3_tile_w(offs_t offset,uint64_t data,uint64_t mem_mask)407 void model3_state::model3_tile_w(offs_t offset, uint64_t data, uint64_t mem_mask)
408 {
409 COMBINE_DATA(&m_m3_tile_ram[offset]);
410
411 /*
412 m_layer4[0]->mark_all_dirty();
413 m_layer8[0]->mark_all_dirty();
414 m_layer4[1]->mark_all_dirty();
415 m_layer8[1]->mark_all_dirty();
416 m_layer4[2]->mark_all_dirty();
417 m_layer8[2]->mark_all_dirty();
418 m_layer4[3]->mark_all_dirty();
419 m_layer8[3]->mark_all_dirty();
420 */
421
422 int layer = (offset >> 10) & 0x3;
423 int tile = (offset & 0x3ff) * 4;
424 m_layer4[layer]->mark_tile_dirty(tile+0);
425 m_layer4[layer]->mark_tile_dirty(tile+1);
426 m_layer4[layer]->mark_tile_dirty(tile+2);
427 m_layer4[layer]->mark_tile_dirty(tile+3);
428 m_layer8[layer]->mark_tile_dirty(tile+0);
429 m_layer8[layer]->mark_tile_dirty(tile+1);
430 m_layer8[layer]->mark_tile_dirty(tile+2);
431 m_layer8[layer]->mark_tile_dirty(tile+3);
432 }
433
434 /*
435 Video registers:
436
437 0xF1180000: ?
438 0xF1180004: ?
439 0xF1180008: ? lostwsga: writes 0x7f010000
440 lemans24, magtruck, von2, lamachin: writes 0xee000000
441 bass, vs2, harley, scud, skichamp, fvipers2, eca: writes 0xef000000
442 srally2, swtrilgy: writes 0x70010000
443 daytona2: writes 0x4f010000
444
445 0xF1180010: VBL IRQ acknowledge
446
447 0xF1180020: xxxxxxxx -------- -------- -------- ?
448 -------- x------- -------- -------- Layer 3 bitdepth (0 = 8-bit, 1 = 4-bit)
449 -------- -x------ -------- -------- Layer 2 bitdepth (0 = 8-bit, 1 = 4-bit)
450 -------- --x----- -------- -------- Layer 1 bitdepth (0 = 8-bit, 1 = 4-bit)
451 -------- ---x---- -------- -------- Layer 0 bitdepth (0 = 8-bit, 1 = 4-bit)
452 -------- ----x--- -------- -------- Layer 3 priority (0 = below 3D, 1 = above 3D)
453 -------- -----x-- -------- -------- Layer 2 priority (0 = below 3D, 1 = above 3D)
454 -------- ------x- -------- -------- Layer 1 priority (0 = below 3D, 1 = above 3D)
455 -------- -------x -------- -------- Layer 0 priority (0 = below 3D, 1 = above 3D)
456
457 0xF1180040: Foreground layer color modulation?
458 -------- xxxxxxxx -------- -------- Red component
459 -------- -------- xxxxxxxx -------- Green component
460 -------- -------- -------- xxxxxxxx Blue component
461
462 0xF1180044: Background layer color modulation?
463 -------- xxxxxxxx -------- -------- Red component
464 -------- -------- xxxxxxxx -------- Green component
465 -------- -------- -------- xxxxxxxx Blue component
466
467 0xF1180060: x------- -------- -------- -------- Layer 0 enable
468 -------x xxxxxxxx -------- -------- Layer 0 Y scroll position
469 -------- -------- -------x xxxxxxxx Layer 0 X scroll position
470
471 0xF1180064: x------- -------- -------- -------- Layer 1 enable
472 -------x xxxxxxxx -------- -------- Layer 1 Y scroll position
473 -------- -------- -------x xxxxxxxx Layer 1 X scroll position
474
475 0xF1180068: x------- -------- -------- -------- Layer 2 enable
476 -------x xxxxxxxx -------- -------- Layer 2 Y scroll position
477 -------- -------- -------x xxxxxxxx Layer 2 X scroll position
478
479 0xF118006C: x------- -------- -------- -------- Layer 3 enable
480 -------x xxxxxxxx -------- -------- Layer 3 Y scroll position
481 -------- -------- -------x xxxxxxxx Layer 3 X scroll position
482 */
483
484
model3_vid_reg_r(offs_t offset)485 uint64_t model3_state::model3_vid_reg_r(offs_t offset)
486 {
487 switch(offset)
488 {
489 case 0x00/8: return m_vid_reg0;
490 case 0x08/8: return 0xffffffffffffffffU; /* ??? */
491 case 0x20/8: return (uint64_t)m_layer_priority << 48;
492 case 0x40/8: return ((uint64_t)m_layer_modulate1 << 32) | (uint64_t)m_layer_modulate2;
493 default: logerror("read reg %02X\n", offset);break;
494 }
495 return 0;
496 }
497
model3_vid_reg_w(offs_t offset,uint64_t data,uint64_t mem_mask)498 void model3_state::model3_vid_reg_w(offs_t offset, uint64_t data, uint64_t mem_mask)
499 {
500 switch(offset)
501 {
502 case 0x00/8: logerror("vid_reg0: %08X%08X\n", (uint32_t)(data>>32),(uint32_t)(data)); m_vid_reg0 = data; break;
503 case 0x08/8: break; /* ??? */
504 case 0x10/8: set_irq_line((data >> 56) & 0x0f, CLEAR_LINE); break; /* VBL IRQ Ack */
505
506 case 0x20/8: m_layer_priority = (data >> 48); break;
507
508 case 0x40/8: m_layer_modulate1 = (uint32_t)(data >> 32);
509 m_layer_modulate2 = (uint32_t)(data);
510 break;
511 case 0x60/8: COMBINE_DATA(&m_layer_scroll[0]); break;
512 case 0x68/8: COMBINE_DATA(&m_layer_scroll[1]); break;
513 default: logerror("model3_vid_reg_w: %02X, %08X%08X\n", offset, (uint32_t)(data >> 32), (uint32_t)(data)); break;
514 }
515 }
516
model3_palette_w(offs_t offset,uint64_t data,uint64_t mem_mask)517 void model3_state::model3_palette_w(offs_t offset, uint64_t data, uint64_t mem_mask)
518 {
519 COMBINE_DATA(&m_paletteram64[offset]);
520 uint32_t data1 = BYTE_REVERSE32((uint32_t)(m_paletteram64[offset] >> 32));
521 uint32_t data2 = BYTE_REVERSE32((uint32_t)(m_paletteram64[offset] >> 0));
522
523 m_palette->set_pen_color((offset*2)+0, pal5bit(data1 >> 0), pal5bit(data1 >> 5), pal5bit(data1 >> 10));
524 m_palette->set_pen_color((offset*2)+1, pal5bit(data2 >> 0), pal5bit(data2 >> 5), pal5bit(data2 >> 10));
525 }
526
model3_palette_r(offs_t offset)527 uint64_t model3_state::model3_palette_r(offs_t offset)
528 {
529 return m_paletteram64[offset];
530 }
531
532
533 /*****************************************************************************/
534 /* texture caching */
535
536 /*
537 array of cached textures:
538 4 potential textures for 4-bit grayscale
539 2 pages
540 1024 pixels / 32 pixel resolution vertically
541 2048 pixels / 32 pixel resolution horizontally
542 */
invalidate_texture(int page,int texx,int texy,int texwidth,int texheight)543 void model3_state::invalidate_texture(int page, int texx, int texy, int texwidth, int texheight)
544 {
545 int wtiles = 1 << texwidth;
546 int htiles = 1 << texheight;
547
548 for (int y = 0; y < htiles; y++)
549 for (int x = 0; x < wtiles; x++)
550 while (m_texcache[page][texy + y][texx + x] != nullptr)
551 {
552 cached_texture *freeme = m_texcache[page][texy + y][texx + x];
553 m_texcache[page][texy + y][texx + x] = freeme->next;
554 auto_free(machine(), freeme);
555 }
556 }
557
get_texture(int page,int texx,int texy,int texwidth,int texheight,int format)558 cached_texture *model3_state::get_texture(int page, int texx, int texy, int texwidth, int texheight, int format)
559 {
560 cached_texture *tex = m_texcache[page][texy][texx];
561 int pixheight = 32 << texheight;
562 int pixwidth = 32 << texwidth;
563 uint32_t alpha = ~0;
564 int x, y;
565
566 /* if we have one already, validate it */
567 for (tex = m_texcache[page][texy][texx]; tex != nullptr; tex = tex->next)
568 if (tex->width == texwidth && tex->height == texheight && tex->format == format)
569 return tex;
570
571 /* create a new texture */
572 tex = (cached_texture *)auto_alloc_array(machine(), uint8_t, sizeof(cached_texture) + (2 * pixwidth * 2 * pixheight) * sizeof(rgb_t));
573 tex->width = texwidth;
574 tex->height = texheight;
575 tex->format = format;
576
577 /* set the new texture */
578 tex->next = m_texcache[page][texy][texx];
579 m_texcache[page][texy][texx] = tex;
580
581 /* decode it */
582 for (y = 0; y < pixheight; y++)
583 {
584 const uint16_t *texsrc = &m_texture_ram[page][(texy * 32 + y) * 2048 + texx * 32];
585 rgb_t *dest = tex->data + 2 * pixwidth * y;
586
587 switch (format)
588 {
589 case 0: /* 1-5-5-5 ARGB */
590 for (x = 0; x < pixwidth; x++)
591 {
592 uint16_t pixdata = texsrc[x];
593 alpha &= dest[x] = rgb_t(pal1bit(~pixdata >> 15), pal5bit(pixdata >> 10), pal5bit(pixdata >> 5), pal5bit(pixdata >> 0));
594 }
595 break;
596
597 case 1: /* A4L4 interleaved */
598 for (x = 0; x < pixwidth; x++)
599 {
600 uint8_t grayvalue = pal4bit(texsrc[x] & 0xf);
601 uint8_t a = pal4bit((texsrc[x] >> 4) & 0xf);
602 alpha &= dest[x] = rgb_t(a, grayvalue, grayvalue, grayvalue);
603 }
604 break;
605
606 case 2: /* A4L4? */
607 for (x = 0; x < pixwidth; x++)
608 {
609 uint8_t grayvalue = pal4bit((texsrc[x] >> 0) & 0xf);
610 uint8_t a = pal4bit((texsrc[x] >> 4) & 0xf);
611 alpha &= dest[x] = rgb_t(a, grayvalue, grayvalue, grayvalue);
612 }
613 break;
614
615 case 3: /* A4L4 interleaved */
616 for (x = 0; x < pixwidth; x++)
617 {
618 uint8_t grayvalue = pal4bit((texsrc[x] >> 8) & 0xf);
619 uint8_t a = pal4bit((texsrc[x] >> 12) & 0xf);
620 alpha &= dest[x] = rgb_t(a, grayvalue, grayvalue, grayvalue);
621 }
622 break;
623
624 case 4: /* 8-bit A4L4 */
625 for (x = 0; x < pixwidth; x++)
626 {
627 uint8_t pixdata = texsrc[x] >> 8;
628 alpha &= dest[x] = rgb_t(pal4bit(pixdata), pal4bit(pixdata >> 4), pal4bit(pixdata >> 4), pal4bit(pixdata >> 4));
629 }
630 break;
631
632 case 5: /* L8 */
633 for (x = 0; x < pixwidth; x++)
634 {
635 uint8_t grayvalue = texsrc[x];
636 alpha &= dest[x] = rgb_t(0xff, grayvalue, grayvalue, grayvalue);
637 }
638 break;
639
640 case 6: /* L8 */
641 for (x = 0; x < pixwidth; x++)
642 {
643 uint8_t grayvalue = texsrc[x] >> 8;
644 alpha &= dest[x] = rgb_t(0xff, grayvalue, grayvalue, grayvalue);
645 }
646 break;
647
648 case 7: /* 4-4-4-4 ARGB */
649 for (x = 0; x < pixwidth; x++)
650 {
651 uint16_t pixdata = texsrc[x];
652 alpha &= dest[x] = rgb_t(pal4bit(pixdata >> 0), pal4bit(pixdata >> 12), pal4bit(pixdata >> 8), pal4bit(pixdata >> 4));
653 }
654 break;
655 }
656
657 /* create the horizontal mirror of this line */
658 for (x = 0; x < pixwidth; x++)
659 dest[pixwidth * 2 - 1 - x] = dest[x];
660 }
661
662 /* create the vertical mirror of the texture */
663 for (y = 0; y < pixheight; y++)
664 memcpy(tex->data + 2 * pixwidth * (pixheight * 2 - 1 - y), tex->data + 2 * pixwidth * y, sizeof(rgb_t) * pixwidth * 2);
665
666 /* remember the overall alpha */
667 tex->alpha = alpha >> 24;
668
669 /* return a pointer to the texture */
670 return tex;
671 }
672
673 /*****************************************************************************/
674 /* Real3D Graphics stuff */
675
676 /*
677 Real3D Pro-1000 capabilities:
678
679 Coordinate sets
680 - 4096 matrices (matrix base pointer in viewport node)
681
682 Polygons
683 - 32MB max polygon memory. VROM in Model 3, the low 4MB of VROM is overlaid by Polygon RAM for runtime generated content.
684
685 Texture
686 - 2 texture sheets of 2048x1024
687 - Mipmaps located in the bottom right corner
688 - Texture size 32x32 to 1024x1024
689 - Microtextures (is this featured in Model 3?)
690
691 LODs
692 - 127 blend types per viewport with 4 sets of min/max angle or range (where is this in the viewport node?)
693
694 Lighting
695 - Self-luminous lighting (enable and luminosity parameter in polygon structure)
696 - Fixed polygon shading, fixed shading weight per vertex (not found in Model 3, yet)
697 - Flat sun shading (lighting parameters in viewport node) needs a separate enable?
698 - Smooth polygon shading (lighting parameters in viewport, use vertex normals)
699
700 Gamma table
701 - 256 entry 8-bit table, possibly in Polygon RAM
702 */
703
704 /*
705 Real3D Memory Structures:
706
707 Culling Nodes:
708 - Located in Culling RAM (0x8E000000)
709 - Limit of 15 child nodes (nesting), not including polygon nodes
710 - Color table (is this featured in Model 3?)
711
712 0x00: xxxxxxxx xxxxxxxx xxxxxx-- -------- Viewport number
713 -------- -------- ------xx -------- Viewport select 0-3
714 -------- -------- -------- x------- Display select
715 -------- -------- -------- -x------ Fix point centroid
716 -------- -------- -------- --x----- Viewport off
717 -------- -------- -------- ---xx--- Viewport priority
718 -------- -------- -------- -----x-- "clr_xlator_tbl_sel"
719 -------- -------- -------- ------xx Node type
720
721 0x01: -------x -------- -------- -------- Sibling null
722 -------- xxxxxxxx xxxxxxxx xxxxxxxx Sibling pointer
723
724 0x02: -----x-- -------- -------- -------- Child is sibling table
725 -------x -------- -------- -------- Leaf node
726 -------- xxxxxxxx xxxxxxxx xxxxxxxx Child pointer
727
728 0x03: "cota" (float) Affected by frustum angles and viewport size
729 0x04: Sun light vector X-component (float)
730 0x05: Sun light vector Y-component (float)
731 0x06: Sun light vector Z-component (float)
732 0x07: Sun light intensity (float)
733 0x08: "Cv" ? (float) Affected by left and right angle
734 0x09: "Cw" ? (float) Affected by top and bottom angle
735 0x0a: "Io" ? (float) Affected by top and bottom angle
736 0x0b: "Jo" ? (float) Affected by left and right angle
737 0x0c: (float) Left clip plane U
738 0x0d: (float) Left clip plane V
739 0x0e: (float) Top clip plane U
740 0x0f: (float) Top clip plane W
741 0x10: (float) Right clip plane U
742 0x11: (float) Right clip plane V
743 0x12: (float) Bottom clip plane U
744 0x13: (float) Bottom clip plane W
745
746 0x14: xxxxxxxx xxxxxxxx -------- -------- Viewport height (14.2 fixed-point)
747 -------- -------- xxxxxxxx xxxxxxxx Viewport width (14.2 fixed-point)
748
749 0x15: xxxxxxxx xxxxxxxx -------- -------- "env_to_chan_matrix_index"
750
751 0x16: -------- xxxxxxxx xxxxxxxx xxxxxxxx Matrix base pointer
752
753 0x17: -------- xxxxxxxx xxxxxxxx xxxxxxxx LOD pointer
754
755 0x18: -------- xxxxxxxx xxxxxxxx xxxxxxxx Culling offset
756
757 0x19: -------- xxxxxxxx xxxxxxxx xxxxxxxx Polygon offset
758
759 0x1a: xxxxxxxx xxxxxxxx -------- -------- Viewport Y coordinate (12.4 fixed-point)
760 -------- -------- xxxxxxxx xxxxxxxx Viewport X coordinate (12.4 fixed-point)
761
762 0x1b: Copy of word 0x00
763
764 0x1c: xxxxxxxx xxxxxxxx -------- -------- "lj"
765 -------- -------- xxxxxxxx xxxxxxxx "li"
766
767 0x1d: -------- xxxxxxxx -------- -------- Spotlight Y size
768 -------- -------- xxxxxxxx xxxxxxxx Spotlight Y position (13.3 fixed-point?)
769
770 0x1e: -------- xxxxxxxx -------- -------- Spotlight X size
771 -------- -------- xxxxxxxx xxxxxxxx Spotlight X position (13.3 fixed-point?)
772
773 0x1f: Light extent (float)
774
775 0x20: xxxxxxxx -------- -------- -------- ?
776 -------- xxxxxxxx -------- -------- ?
777 -------- -------- -x------ -------- Parallel projection
778 -------- -------- --xxx--- -------- Light RGB (RGB111?)
779 -------- -------- -----xxx -------- Light RGB Fog (RGB111?)
780 -------- -------- -------- xxxxxxxx Scroll Fog (0.8 fixed-point?) What is this???
781
782 0x21: "inv_light_start_range" (float)
783 0x22: Fog Color (RGB888)
784 0x23: Fog Density (float)
785
786 0x24: -------- xxxxxxxx -------- -------- Fog attenuation
787 -------- -------- xxxxxxxx -------- Sun light ambient (0.8 fixed-point)
788 -------- -------- -------- xxxxxxxx Scroll attenuation (0.8 fixed-point) What is this???
789
790 0x25: -------- xxxxxxxx -------- -------- Ambient fog
791 -------- -------- xxxxxxxx xxxxxxxx Fog offset
792
793 0x26: xxxxxxxx xxxxxxxx xxxxxxxx -------- Spot light
794 -------- -------- -------- x------- Clear viewport
795 -------- -------- -------- -x------ New sun parameters
796
797 0x27: x------- -------- -------- -------- Valid spot light
798 -x------ -------- -------- -------- Pro 1000 dummy
799 -------- --xxxxxx xxxxxxxx xxxxxxxx "upgrade_wd_10"
800
801 0x28: Fog layer altitude (float)
802
803 0x29: Top fog density (float)
804
805 0x2a: Bottom fog density (float)
806
807 0x2b: Near clipping plane (float)
808
809 0x2c: Far clipping plane (float)
810
811 0x2d: Pfog offset top
812
813 0x2e: Pfog offset bottom
814 0x2f: ?
815
816
817 Sub types:
818 LOD Culling Node. Up to 4 LODs.
819
820 Articulated Part Culling Node (is this used by Model 3?)
821 - An Articulated Part culling node, or six degree?of?freedom node, is used to define
822 geometry that can move relative to the parent coordinate set to which it is attached.
823 Fifteen levels of coordinate set nesting (levels of articulation) are supported.
824
825 Animation Culling Node
826 - Animation culling nodes are used to build a culling hierarchy for an object with different
827 representations, or animation frames. which can be turned on and off by the
828 application. Each child (culling node or polygon) added to an Animation culling node
829 specifies the frame for which the child is valid.
830
831 Instance Culling Node
832 - Instance culling nodes define the top of a shared display list segment that can be
833 referenced from other parts of the scene display list.
834
835 Instance Reference Culling Node
836 - An Instance Reference node is considered a leaf node; its
837 "child" is the shared geometry segment. An Instance Reference may be attached to
838 a parent node and may not have any other children, but may have siblings.
839
840 Point Light
841 - A Point Light is used to create an instance of a point luminous feature. The size,
842 feature type, and number of sides of the point light model may be customized.
843
844 Instance Set
845 - An Instance Set is a culling node which defines a set of point features. Each feature
846 is positioned individually. This type of culling node can be used to simulate particles.
847
848
849
850 Instance Node?
851
852 0x00: x------- -------- -------- -------- Is UF ref
853 -x------ -------- -------- -------- Is 3D model
854 --x----- -------- -------- -------- Is point
855 ---x---- -------- -------- -------- Is point ref
856 ----x--- -------- -------- -------- Is animation
857 -----x-- -------- -------- -------- Is billboard
858 ------x- -------- -------- -------- Child is billboard
859 -------x -------- -------- -------- Extra child pointer needed
860 -------- -----xxx xxxxxx-- -------- Node ID
861
862 -------- -------- -------- x------- Reset matrix
863 -------- -------- -------- -x------ Use child pointer
864 -------- -------- -------- --x----- Use sibling pointer
865 -------- -------- -------- ---x---- No matrix
866 -------- -------- -------- ----x--- Indirect child
867 -------- -------- -------- -----x-- Valid color table
868 -------- -------- -------- ------xx Node type (0 = viewport, 1 = root node, 2 = culling node)
869
870 0x01,0x02 only present on Step 2+
871
872 0x01: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Model scale (float)
873 0x02: -------- -------- x------- -------- Texture replace
874 -------- -------- -x------ -------- Switch bank
875 -------- -------- --xxxxxx x------- X offset
876 -------- -------- -------- -xxxxxxx Y offset
877
878 0x03: xxxxxxxx xxxxx--- -------- -------- Color table address 1
879 -------- -----xxx xxxx---- -------- LOD table pointer
880 -------- -------- ----xxxx xxxxxxxx Node matrix
881
882 0x04: Translation X coordinate
883 0x05: Translation Y coordinate
884 0x06: Translation Z coordinate
885
886 0x07: xxxx---- -------- -------- -------- Color table address 2
887 -----x-- -------- -------- -------- Sibling table
888 ------x- -------- -------- -------- Point
889 -------x -------- -------- -------- Leaf node
890 -------- xxxxxxxx xxxxxxxx xxxxxxxx Child pointer
891
892 0x08: xxxxxxx- -------- -------- -------- Color table address 3
893 -------x -------- -------- -------- Null sibling
894 -------- xxxxxxxx xxxxxxxx xxxxxxxx Sibling pointer
895
896 0x09: xxxxxxxx xxxxxxxx -------- -------- Blend radius
897 -------- -------- xxxxxxxx xxxxxxxx Culling radius
898
899
900 Polygon Data
901
902 0x00: xxxxxx-- -------- -------- -------- Specular
903 ------x- -------- -------- -------- Clockwise data
904 -------x xxxxxxxx xxxxxx-- -------- Polygon ID
905 -------- -------- ------xx -------- Discard this polygon
906 -------- -------- -------- x------- Specular enable
907 -------- -------- -------- -x------ 0 = Triangle, 1 = Quad
908 -------- -------- -------- --x----- Polygon is points
909 -------- -------- -------- ---x---- Smoothing enable
910 -------- -------- -------- ----x--- Vertex 3 shared from previous polygon
911 -------- -------- -------- -----x-- Vertex 2 shared from previous polygon
912 -------- -------- -------- ------x- Vertex 1 shared from previous polygon
913 -------- -------- -------- -------x Vertex 0 shared from previous polygon
914
915
916 0x01: xxxxxxxx xxxxxxxx xxxxxxxx -------- Polygon normal X coordinate (2.22 fixed point)
917 -------- -------- -------- x------- Edge on translucency
918 -------- -------- -------- -x------ UV format (0 = 13.3, 1 = 16.0)
919 -------- -------- -------- --x----- Enable fixed shading
920 -------- -------- -------- ---x---- Enable double-sided polygon
921 -------- -------- -------- ----x--- Enable smooth shading
922 -------- -------- -------- -----x-- If set, this is the last polygon
923 -------- -------- -------- ------x- Poly color, 1 = RGB, 0 = color table
924 -------- -------- -------- -------x No LOS return
925
926
927 0x02: xxxxxxxx xxxxxxxx xxxxxxxx -------- Polygon normal Y coordinate (2.22 fixed point)
928 -------- -------- -------- xxx----- Microtexture select
929 -------- -------- -------- ---x---- Microtexture enable
930 -------- -------- -------- ----xx-- Microtexture min LOD
931 -------- -------- -------- ------x- Texture U mirror enable
932 -------- -------- -------- -------x Texture V mirror enable
933
934 0x03: xxxxxxxx xxxxxxxx xxxxxxxx -------- Polygon normal Z coordinate (2.22 fixed point)
935 -------- -------- -------- x------- X wrap smoothing
936 -------- -------- -------- -x------ Y wrap smoothing
937 -------- -------- -------- --xxx--- Texture width (in 8-pixel tiles)
938 -------- -------- -------- -----xxx Texture height (in 8-pixel tiles)
939
940 0x04: xxxxxxxx xxxxxxxx xxxxxxxx -------- Color (RGB888)
941 -------- -------- -------- x------- Translator map select
942 -------- -------- -------- -x------ Texture page
943 -------- -------- -------- --xxxxxx Upper 6 bits of texture U coordinate
944
945 0x05: xxxxxxxx xxxxxxxx xxxxxxxx -------- Texture NP scale
946 -------- -------- -------- x------- Low bit of texture U coordinate
947 -------- -------- -------- ---xxxxx Low 5 bits of texture V coordinate
948 -------- -------- -------- -xx----- Top 2 bits of texture V coordinate (unused by Model 3)
949
950 0x06: x------- -------- -------- -------- Texture contour enable
951 -xxxxxxx -------- -------- -------- Translator map offset
952 -------- xxxxxx-- -------- -------- Polygon translucency
953 -------- ------x- -------- -------- Translucency pattern select
954 -------- -------x -------- -------- 1 = disable lighting
955 -------- -------- xxxxx--- -------- Polygon light modifier (Amount that a luminous polygon will burn through fog.
956 Valid range is 0.0 to 1.0. 0.0 is completely fogged;
957 1.0 has no fog.)
958 -------- -------- -----x-- -------- Texture enable
959 -------- -------- ------xx x------- Texture format
960 -------- -------- -------- -xx----- Shininess
961 -------- -------- -------- ---x---- High priority polygon
962 -------- -------- -------- ----x--- Layered polygon (stencil)
963 -------- -------- -------- -----xxx Translucency mode
964
965
966 Vertex entry
967
968 0x00: xxxxxxxx xxxxxxxx xxxxxxxx -------- Vertex X coordinate (17.7 fixed-point in Step 1.0, 13.11 otherwise)
969 -------- -------- -------- xxxxxxxx Vertex normal X
970
971 0x01: xxxxxxxx xxxxxxxx xxxxxxxx -------- Vertex Y coordinate
972 -------- -------- -------- xxxxxxxx Vertex normal Y
973
974 0x02: xxxxxxxx xxxxxxxx xxxxxxxx -------- Vertex Z coordinate
975 -------- -------- -------- xxxxxxxx Vertex normal Z
976
977 0x03: xxxxxxxx xxxxxxxx -------- -------- Vertex U coordinate
978 -------- -------- xxxxxxxx xxxxxxxx Vertex V coordinate
979
980 */
981
982
real3d_display_list_w(offs_t offset,uint64_t data,uint64_t mem_mask)983 void model3_state::real3d_display_list_w(offs_t offset, uint64_t data, uint64_t mem_mask)
984 {
985 if (ACCESSING_BITS_32_63)
986 {
987 m_display_list_ram[offset*2] = BYTE_REVERSE32((uint32_t)(data >> 32));
988 }
989 if (ACCESSING_BITS_0_31)
990 {
991 m_display_list_ram[(offset*2)+1] = BYTE_REVERSE32((uint32_t)(data));
992 }
993 }
994
real3d_polygon_ram_w(offs_t offset,uint64_t data,uint64_t mem_mask)995 void model3_state::real3d_polygon_ram_w(offs_t offset, uint64_t data, uint64_t mem_mask)
996 {
997 if (ACCESSING_BITS_32_63)
998 {
999 m_polygon_ram[offset*2] = BYTE_REVERSE32((uint32_t)(data >> 32));
1000 }
1001 if (ACCESSING_BITS_0_31)
1002 {
1003 m_polygon_ram[(offset*2)+1] = BYTE_REVERSE32((uint32_t)(data));
1004 }
1005 }
1006
1007 static const uint8_t texture_decode16[64] =
1008 {
1009 0, 1, 4, 5, 8, 9, 12, 13,
1010 2, 3, 6, 7, 10, 11, 14, 15,
1011 16, 17, 20, 21, 24, 25, 28, 29,
1012 18, 19, 22, 23, 26, 27, 30, 31,
1013 32, 33, 36, 37, 40, 41, 44, 45,
1014 34, 35, 38, 39, 42, 43, 46, 47,
1015 48, 49, 52, 53, 56, 57, 60, 61,
1016 50, 51, 54, 55, 58, 59, 62, 63
1017 };
1018
1019 static const uint8_t texture_decode8[32] =
1020 {
1021 1, 3, 5, 7,
1022 0, 2, 4, 6,
1023 9, 11, 13, 15,
1024 8, 10, 12, 14,
1025 17, 19, 21, 23,
1026 16, 18, 20, 22,
1027 25, 27, 29, 31,
1028 24, 26, 28, 30
1029 };
1030
write_texture16(int xpos,int ypos,int width,int height,int page,uint16_t * data)1031 inline void model3_state::write_texture16(int xpos, int ypos, int width, int height, int page, uint16_t *data)
1032 {
1033 int x,y,i,j;
1034
1035 for(y=ypos; y < ypos+height; y+=8)
1036 {
1037 for(x=xpos; x < xpos+width; x+=8)
1038 {
1039 uint16_t *texture = &m_texture_ram[page][y*2048+x];
1040 int b = 0;
1041 for(j=y; j < y+8; j++) {
1042 for(i=x; i < x+8; i++) {
1043 *texture++ = data[texture_decode16[b^1]];
1044 ++b;
1045 }
1046 texture += 2048-8;
1047 }
1048 data += 64;
1049 }
1050 }
1051 }
1052
write_texture8(int xpos,int ypos,int width,int height,int page,int upper,int lower,uint16_t * data)1053 inline void model3_state::write_texture8(int xpos, int ypos, int width, int height, int page, int upper, int lower, uint16_t *data)
1054 {
1055 int x,y,i,j;
1056
1057 for(y=ypos; y < ypos+height; y+=8)
1058 {
1059 for(x=xpos; x < xpos+width; x+=8)
1060 {
1061 uint16_t *texture = &m_texture_ram[page][y*2048+x];
1062 int b = 0;
1063 for(j=y; j < y+8; j++)
1064 {
1065 for(i=x; i < x+8; i+=2)
1066 {
1067 uint16_t d = data[texture_decode8[b]];
1068
1069 if (upper)
1070 *texture = (*texture & 0xff) | (d & 0xff00);
1071 if (lower)
1072 *texture = (*texture & 0xff00) | ((d >> 8) & 0xff);
1073 texture++;
1074
1075 if (upper)
1076 *texture = (*texture & 0xff) | ((d & 0xff) << 8);
1077 if (lower)
1078 *texture = (*texture & 0xff00) | (d & 0xff);
1079 texture++;
1080
1081 ++b;
1082 }
1083 texture += 2048-8;
1084 }
1085 data += 32;
1086 }
1087 }
1088 }
1089
1090 /*
1091 Texture header:
1092
1093 -------- -------- -------- --xxxxxx X-position
1094 -------- -------- ----xxxx x------- Y-position
1095 -------- -------x xx------ -------- Width
1096 -------- ----xxx- -------- -------- Height
1097 -------- ---x---- -------- -------- Texture page
1098 -------- --x----- -------- -------- Write 8-bit data to the lower byte of texel
1099 -------- -x------ -------- -------- Write 8-bit data to the upper byte of texel
1100 -------- x------- -------- -------- Bitdepth, 0 = 8-bit, 1 = 16-bit
1101 xxxxxxxx -------- -------- -------- Texture type
1102 0x00 = texture with mipmaps
1103 0x01 = texture without mipmaps
1104 0x02 = only mipmaps
1105 0x80 = possibly gamma table
1106
1107 */
1108
1109 static const int mipmap_coords[9][2] =
1110 {
1111 { 1024, 512 },
1112 { 1536, 768 },
1113 { 1792, 896 },
1114 { 1920, 960 },
1115 { 1984, 992 },
1116 { 2016, 1008 },
1117 { 2032, 1016 },
1118 { 2040, 1020 },
1119 { 2044, 1022 },
1120 };
1121
1122 static const int mipmap_divider[9] = { 2, 4, 8, 16, 32, 64, 128, 256, 512 };
1123
real3d_upload_texture(uint32_t header,uint32_t * data)1124 void model3_state::real3d_upload_texture(uint32_t header, uint32_t *data)
1125 {
1126 int width = 32 << ((header >> 14) & 0x7);
1127 int height = 32 << ((header >> 17) & 0x7);
1128 int xpos = (header & 0x3f) * 32;
1129 int ypos = ((header >> 7) & 0x1f) * 32;
1130 int page = (header >> 20) & 0x1;
1131 int bitdepth = (header >> 23) & 0x1;
1132 int upper_byte = (header >> 22) & 0x1;
1133 int lower_byte = (header >> 21) & 0x1;
1134
1135 //printf("write tex: %08X, w %d, h %d, x %d, y %d, p %d, b %d\n", header, width, height, xpos, ypos, page, bitdepth);
1136
1137 switch(header >> 24)
1138 {
1139 case 0x00: /* Texture with mipmaps */
1140 {
1141 int x = xpos;
1142 int y = ypos;
1143 int w = width;
1144 int h = height;
1145
1146 int mipmap = 0;
1147
1148 while (w >= 8 && h >= 8)
1149 {
1150 if (bitdepth)
1151 {
1152 write_texture16(x, y, w, h, page, (uint16_t*)data);
1153 }
1154 else
1155 {
1156 //printf("write tex8: %08X, w %d, h %d, x %d, y %d, p %d, b %d\n", header, width, height, xpos, ypos, page, bitdepth);
1157 write_texture8(x, y, w, h, page, upper_byte, lower_byte, (uint16_t*)data);
1158 }
1159
1160 data += (w * h * (bitdepth ? 2 : 1)) / 4;
1161 w /= 2;
1162 h /= 2;
1163
1164 x = mipmap_coords[mipmap][0] + (xpos / mipmap_divider[mipmap]);
1165 y = mipmap_coords[mipmap][1] + (ypos / mipmap_divider[mipmap]);
1166 mipmap++;
1167 }
1168
1169 invalidate_texture(page, header & 0x3f, (header >> 7) & 0x1f, (header >> 14) & 0x7, (header >> 17) & 0x7);
1170 break;
1171 }
1172 case 0x01: /* Texture without mipmaps */
1173 {
1174 if (bitdepth)
1175 {
1176 write_texture16(xpos, ypos, width, height, page, (uint16_t*)data);
1177 }
1178 else
1179 {
1180 //printf("write tex8: %08X, w %d, h %d, x %d, y %d, p %d, b %d\n", header, width, height, xpos, ypos, page, bitdepth);
1181 write_texture8(xpos, ypos, width, height, page, upper_byte, lower_byte, (uint16_t*)data);
1182 }
1183
1184 invalidate_texture(page, header & 0x3f, (header >> 7) & 0x1f, (header >> 14) & 0x7, (header >> 17) & 0x7);
1185 break;
1186 }
1187 case 0x02: /* Only mipmaps */
1188 {
1189 int x = mipmap_coords[0][0] + (xpos / mipmap_divider[0]);
1190 int y = mipmap_coords[0][1] + (ypos / mipmap_divider[0]);
1191 int w = width / 2;
1192 int h = height / 2;
1193
1194 int mipmap = 1;
1195
1196 while (w >= 8 && h >= 8)
1197 {
1198 if (bitdepth)
1199 {
1200 write_texture16(x, y, w, h, page, (uint16_t*)data);
1201 }
1202 else
1203 {
1204 //printf("write tex8: %08X, w %d, h %d, x %d, y %d, p %d, b %d\n", header, width, height, xpos, ypos, page, bitdepth);
1205 write_texture8(x, y, w, h, page, upper_byte, lower_byte, (uint16_t*)data);
1206 }
1207
1208 data += (w * h * (bitdepth ? 2 : 1)) / 4;
1209 w /= 2;
1210 h /= 2;
1211
1212 x = mipmap_coords[mipmap][0] + (xpos / mipmap_divider[mipmap]);
1213 y = mipmap_coords[mipmap][1] + (ypos / mipmap_divider[mipmap]);
1214 mipmap++;
1215 }
1216
1217 invalidate_texture(page, header & 0x3f, (header >> 7) & 0x1f, (header >> 14) & 0x7, (header >> 17) & 0x7);
1218 break;
1219 }
1220 case 0x80: /* Gamma-table ? */
1221 break;
1222 default:
1223 fatalerror("Unknown texture type: %02X (%08X)\n", header >> 24, header);
1224 break;
1225 }
1226 }
1227
real3d_display_list_end()1228 void model3_state::real3d_display_list_end()
1229 {
1230 /* upload textures if there are any in the FIFO */
1231 if (m_texture_fifo_pos > 0)
1232 {
1233 int i = 0;
1234 while (i < m_texture_fifo_pos)
1235 {
1236 int length = (m_texture_fifo[i] / 2) + 2;
1237 uint32_t header = m_texture_fifo[i+1];
1238 real3d_upload_texture(header, &m_texture_fifo[i+2]);
1239 i += length;
1240 };
1241 }
1242 m_texture_fifo_pos = 0;
1243
1244 m_renderer->clear_fb();
1245
1246 reset_triangle_buffers();
1247 real3d_traverse_display_list();
1248
1249 for (int i=0; i < 4; i++)
1250 {
1251 int ticount, tiacount;
1252 int ti = m_viewport_tri_index[i];
1253 int tia = m_viewport_tri_alpha_index[i];
1254 if (i < 3)
1255 {
1256 ticount = m_viewport_tri_index[i+1] - ti;
1257 tiacount = m_viewport_tri_alpha_index[i+1] - tia;
1258 }
1259 else
1260 {
1261 ticount = m_tri_buffer_ptr - ti;
1262 tiacount = m_tri_alpha_buffer_ptr - tia;
1263 }
1264
1265 if (ticount > 0 || tiacount > 0)
1266 {
1267 m_renderer->clear_zb();
1268 m_renderer->draw_opaque_triangles(&m_tri_buffer[ti], ticount);
1269 m_renderer->draw_alpha_triangles(&m_tri_alpha_buffer[tia], tiacount);
1270 m_renderer->wait_for_polys();
1271 }
1272 }
1273 }
1274
real3d_display_list1_dma(uint32_t src,uint32_t dst,int length,int byteswap)1275 void model3_state::real3d_display_list1_dma(uint32_t src, uint32_t dst, int length, int byteswap)
1276 {
1277 address_space &space = m_maincpu->space(AS_PROGRAM);
1278 int d = (dst & 0xffffff) / 4;
1279 for (int i = 0; i < length; i += 4)
1280 {
1281 uint32_t w = space.read_dword(src);
1282
1283 if (byteswap)
1284 w = BYTE_REVERSE32(w);
1285
1286 m_display_list_ram[d++] = w;
1287 src += 4;
1288 }
1289 }
1290
real3d_display_list2_dma(uint32_t src,uint32_t dst,int length,int byteswap)1291 void model3_state::real3d_display_list2_dma(uint32_t src, uint32_t dst, int length, int byteswap)
1292 {
1293 address_space &space = m_maincpu->space(AS_PROGRAM);
1294 int d = (dst & 0xffffff) / 4;
1295 for (int i = 0; i < length; i += 4)
1296 {
1297 uint32_t w = space.read_dword(src);
1298
1299 if (byteswap)
1300 w = BYTE_REVERSE32(w);
1301
1302 m_culling_ram[d++] = w;
1303 src += 4;
1304 }
1305 }
1306
real3d_vrom_texture_dma(uint32_t src,uint32_t dst,int length,int byteswap)1307 void model3_state::real3d_vrom_texture_dma(uint32_t src, uint32_t dst, int length, int byteswap)
1308 {
1309 address_space &space = m_maincpu->space(AS_PROGRAM);
1310 if ((dst & 0xff) == 0)
1311 {
1312 for (int i=0; i < length; i+=12)
1313 {
1314 uint32_t address = space.read_dword(src+i+0);
1315 uint32_t header = space.read_dword(src+i+4);
1316
1317 if (byteswap)
1318 {
1319 address = BYTE_REVERSE32(address);
1320 header = BYTE_REVERSE32(header);
1321 }
1322
1323 real3d_upload_texture(header, (uint32_t*)&m_vrom[address]);
1324 }
1325 }
1326 }
1327
real3d_texture_fifo_dma(uint32_t src,int length,int byteswap)1328 void model3_state::real3d_texture_fifo_dma(uint32_t src, int length, int byteswap)
1329 {
1330 address_space &space = m_maincpu->space(AS_PROGRAM);
1331 for (int i = 0; i < length; i += 4)
1332 {
1333 uint32_t w = space.read_dword(src);
1334
1335 if (byteswap)
1336 w = BYTE_REVERSE32(w);
1337
1338 m_texture_fifo[m_texture_fifo_pos] = w;
1339 m_texture_fifo_pos++;
1340 src += 4;
1341 }
1342 }
1343
real3d_polygon_ram_dma(uint32_t src,uint32_t dst,int length,int byteswap)1344 void model3_state::real3d_polygon_ram_dma(uint32_t src, uint32_t dst, int length, int byteswap)
1345 {
1346 address_space &space = m_maincpu->space(AS_PROGRAM);
1347 int d = (dst & 0xffffff) / 4;
1348 for (int i = 0; i < length; i += 4)
1349 {
1350 uint32_t w = space.read_dword(src);
1351
1352 if (byteswap)
1353 w = BYTE_REVERSE32(w);
1354
1355 m_polygon_ram[d++] = w;
1356 src += 4;
1357 }
1358 }
1359
real3d_cmd_w(uint64_t data)1360 void model3_state::real3d_cmd_w(uint64_t data)
1361 {
1362 real3d_display_list_end();
1363 }
1364
1365
1366 /*****************************************************************************/
1367 /* matrix and vector operations */
1368
dot_product3(VECTOR3 a,VECTOR3 b)1369 static inline float dot_product3(VECTOR3 a, VECTOR3 b)
1370 {
1371 return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
1372 }
1373
1374 /* multiplies a 4-element vector by a 4x4 matrix */
matrix_multiply_vector(MATRIX matrix,const VECTOR v,VECTOR * p)1375 static void matrix_multiply_vector(MATRIX matrix, const VECTOR v, VECTOR *p)
1376 {
1377 (*p)[0] = (v[0] * matrix[0][0]) + (v[1] * matrix[1][0]) + (v[2] * matrix[2][0]) + (v[3] * matrix[3][0]);
1378 (*p)[1] = (v[0] * matrix[0][1]) + (v[1] * matrix[1][1]) + (v[2] * matrix[2][1]) + (v[3] * matrix[3][1]);
1379 (*p)[2] = (v[0] * matrix[0][2]) + (v[1] * matrix[1][2]) + (v[2] * matrix[2][2]) + (v[3] * matrix[3][2]);
1380 (*p)[3] = (v[0] * matrix[0][3]) + (v[1] * matrix[1][3]) + (v[2] * matrix[2][3]) + (v[3] * matrix[3][3]);
1381 }
1382
1383 /* multiplies a 4x4 matrix with another 4x4 matrix */
matrix_multiply(MATRIX a,MATRIX b,MATRIX * out)1384 static void matrix_multiply(MATRIX a, MATRIX b, MATRIX *out)
1385 {
1386 int i,j;
1387 MATRIX tmp;
1388
1389 for( i=0; i < 4; i++ ) {
1390 for( j=0; j < 4; j++ ) {
1391 tmp[i][j] = (a[i][0] * b[0][j]) + (a[i][1] * b[1][j]) + (a[i][2] * b[2][j]) + (a[i][3] * b[3][j]);
1392 }
1393 }
1394 memcpy(out, &tmp, sizeof(MATRIX));
1395 }
1396
init_matrix_stack()1397 void model3_state::init_matrix_stack()
1398 {
1399 MATRIX *matrix_stack;
1400 matrix_stack = m_matrix_stack = auto_alloc_array_clear(machine(), MATRIX, MATRIX_STACK_SIZE);
1401
1402 /* initialize the first matrix as identity */
1403 matrix_stack[0][0][0] = 1.0f;
1404 matrix_stack[0][0][1] = 0.0f;
1405 matrix_stack[0][0][2] = 0.0f;
1406 matrix_stack[0][0][3] = 0.0f;
1407 matrix_stack[0][1][0] = 0.0f;
1408 matrix_stack[0][1][1] = 1.0f;
1409 matrix_stack[0][1][2] = 0.0f;
1410 matrix_stack[0][1][3] = 0.0f;
1411 matrix_stack[0][2][0] = 0.0f;
1412 matrix_stack[0][2][1] = 0.0f;
1413 matrix_stack[0][2][2] = 1.0f;
1414 matrix_stack[0][2][3] = 0.0f;
1415 matrix_stack[0][3][0] = 0.0f;
1416 matrix_stack[0][3][1] = 0.0f;
1417 matrix_stack[0][3][2] = 0.0f;
1418 matrix_stack[0][3][3] = 1.0f;
1419
1420 m_matrix_stack_ptr = 0;
1421 }
1422
get_top_matrix(MATRIX * out)1423 void model3_state::get_top_matrix(MATRIX *out)
1424 {
1425 memcpy(out, &m_matrix_stack[m_matrix_stack_ptr], sizeof(MATRIX));
1426 }
1427
push_matrix_stack()1428 void model3_state::push_matrix_stack()
1429 {
1430 m_matrix_stack_ptr++;
1431 if (m_matrix_stack_ptr >= MATRIX_STACK_SIZE)
1432 fatalerror("push_matrix_stack: matrix stack overflow\n");
1433
1434 memcpy(&m_matrix_stack[m_matrix_stack_ptr], &m_matrix_stack[m_matrix_stack_ptr - 1], sizeof(MATRIX));
1435 }
1436
pop_matrix_stack()1437 void model3_state::pop_matrix_stack()
1438 {
1439 m_matrix_stack_ptr--;
1440 if (m_matrix_stack_ptr < 0)
1441 fatalerror("pop_matrix_stack: matrix stack underflow\n");
1442 }
1443
multiply_matrix_stack(MATRIX matrix)1444 void model3_state::multiply_matrix_stack(MATRIX matrix)
1445 {
1446 matrix_multiply(matrix, m_matrix_stack[m_matrix_stack_ptr], &m_matrix_stack[m_matrix_stack_ptr]);
1447 }
1448
translate_matrix_stack(float x,float y,float z)1449 void model3_state::translate_matrix_stack(float x, float y, float z)
1450 {
1451 MATRIX tm;
1452
1453 tm[0][0] = 1.0f; tm[0][1] = 0.0f; tm[0][2] = 0.0f; tm[0][3] = 0.0f;
1454 tm[1][0] = 0.0f; tm[1][1] = 1.0f; tm[1][2] = 0.0f; tm[1][3] = 0.0f;
1455 tm[2][0] = 0.0f; tm[2][1] = 0.0f; tm[2][2] = 1.0f; tm[2][3] = 0.0f;
1456 tm[3][0] = x; tm[3][1] = y; tm[3][2] = z; tm[3][3] = 1.0f;
1457
1458 matrix_multiply(tm, m_matrix_stack[m_matrix_stack_ptr], &m_matrix_stack[m_matrix_stack_ptr]);
1459 }
1460
set_projection(float left,float right,float top,float bottom,float near,float far)1461 void model3_state::set_projection(float left, float right, float top, float bottom, float near, float far)
1462 {
1463 float l = near * tanf(left * 0.5f);
1464 float r = near * tanf(right * 0.5f);
1465 float t = near * tanf(top * 0.5f );
1466 float b = near * tanf(bottom * 0.5f);
1467
1468 m_projection_matrix[0][0] = (2.0f * near) / (l - r);
1469 m_projection_matrix[0][1] = 0.0f;
1470 m_projection_matrix[0][2] = (r + l) / (r - l);
1471 m_projection_matrix[0][3] = 0.0f;
1472 m_projection_matrix[1][0] = 0.0f;
1473 m_projection_matrix[1][1] = (2.0f * near) / (t - b);
1474 m_projection_matrix[1][2] = (t + b) / (t - b);
1475 m_projection_matrix[1][3] = 0.0f;
1476 m_projection_matrix[2][0] = 0.0f;
1477 m_projection_matrix[2][1] = 0.0f;
1478 m_projection_matrix[2][2] = -(far + near) / (far - near);
1479 m_projection_matrix[2][3] = -(2.0f * far * near) / (far - near);
1480 m_projection_matrix[3][0] = 0.0f;
1481 m_projection_matrix[3][1] = 0.0f;
1482 m_projection_matrix[3][2] = -1.0f;
1483 m_projection_matrix[3][3] = 0.0f;
1484 }
1485
1486 /*****************************************************************************/
1487 /* transformation and rasterizing */
1488
reset_triangle_buffers()1489 void model3_state::reset_triangle_buffers()
1490 {
1491 m_tri_buffer_ptr = 0;
1492 m_tri_alpha_buffer_ptr = 0;
1493 }
1494
push_triangle(bool alpha)1495 m3_triangle *model3_state::push_triangle(bool alpha)
1496 {
1497 if (!alpha)
1498 {
1499 int i = m_tri_buffer_ptr;
1500
1501 if (m_tri_buffer_ptr >= TRI_BUFFER_SIZE)
1502 {
1503 return nullptr;
1504 //fatalerror("push_triangle: tri buffer max exceeded");
1505 }
1506
1507 m_tri_buffer_ptr++;
1508 return &m_tri_buffer[i];
1509 }
1510 else
1511 {
1512 int i = m_tri_alpha_buffer_ptr;
1513
1514 if (m_tri_alpha_buffer_ptr >= TRI_ALPHA_BUFFER_SIZE)
1515 {
1516 return nullptr;
1517 //fatalerror("push_triangle: tri alpha buffer max exceeded");
1518 }
1519
1520 m_tri_alpha_buffer_ptr++;
1521 return &m_tri_alpha_buffer[i];
1522 }
1523 }
1524
draw_model(uint32_t addr)1525 void model3_state::draw_model(uint32_t addr)
1526 {
1527 // Polygon RAM is mapped to the low 4MB of VROM
1528 uint32_t *model = (addr >= 0x100000) ? &m_vrom[addr] : &m_polygon_ram[addr];
1529
1530 uint32_t header[7];
1531 int index = 0;
1532 bool last_polygon = false, first_polygon = true, back_face = false;
1533 int num_vertices;
1534 int i, v, vi;
1535 float fixed_point_fraction;
1536 m3_vertex vertex[4];
1537 m3_vertex prev_vertex[4];
1538 m3_clip_vertex clip_vert[10];
1539
1540 MATRIX transform_matrix;
1541 MATRIX vp_matrix;
1542 MATRIX coord_matrix;
1543
1544 memset(&coord_matrix, 0, sizeof(coord_matrix));
1545 coord_matrix[0][0] = m_coordinate_system[0][1];
1546 coord_matrix[1][1] = m_coordinate_system[1][2];
1547 coord_matrix[2][2] = -m_coordinate_system[2][0];
1548 coord_matrix[3][3] = 1.0f;
1549
1550 if (m_step < 0x15) // position coordinates are 17.7 fixed-point in Step 1.0
1551 fixed_point_fraction = 1.0f / 128.0f;
1552 else // 13.11 fixed-point in other Steps
1553 fixed_point_fraction = 1.0f / 2048.0f;
1554
1555 get_top_matrix(&transform_matrix);
1556
1557 // make view-projection matrix
1558 matrix_multiply(transform_matrix, coord_matrix, &transform_matrix);
1559 matrix_multiply(transform_matrix, m_projection_matrix, &vp_matrix);
1560
1561 memset(prev_vertex, 0, sizeof(prev_vertex));
1562
1563 while (!last_polygon)
1564 {
1565 float texture_coord_scale;
1566 uint32_t color;
1567 VECTOR3 normal;
1568 VECTOR3 sn;
1569 VECTOR p[4];
1570 int polygon_transparency;
1571
1572 for (i = 0; i < 7; i++)
1573 header[i] = model[index++];
1574
1575 if (first_polygon && (header[0] & 0x0f) != 0)
1576 return;
1577 first_polygon = false;
1578
1579 if (header[6] == 0)
1580 return;
1581
1582 if (header[1] & 0x4)
1583 last_polygon = true;
1584
1585 if ((header[0] & 0x300) == 0x300) // TODO: broken polygons in srally2 have these bits set
1586 return;
1587
1588 num_vertices = (header[0] & 0x40) ? 4 : 3;
1589
1590 /* texture coordinates are 16.0 or 13.3 fixed-point */
1591 texture_coord_scale = (header[1] & 0x40) ? 1.0f : (1.0f / 8.0f);
1592
1593 /* polygon normal (sign + 1.22 fixed-point) */
1594 normal[0] = (float)((int32_t)header[1] >> 8) * (1.0f / 4194304.0f);
1595 normal[1] = (float)((int32_t)header[2] >> 8) * (1.0f / 4194304.0f);
1596 normal[2] = (float)((int32_t)header[3] >> 8) * (1.0f / 4194304.0f);
1597
1598 /* load reused vertices */
1599 vi = 0;
1600 for (v = 0; v < 4; v++)
1601 if (header[0] & (1 << v))
1602 vertex[vi++] = prev_vertex[v];
1603
1604 /* load new vertices */
1605 for ( ; vi < num_vertices; vi++)
1606 {
1607 uint32_t xw = model[index++];
1608 uint32_t yw = model[index++];
1609 uint32_t zw = model[index++];
1610
1611 vertex[vi].x = (float)((int32_t)(xw) >> 8) * fixed_point_fraction;
1612 vertex[vi].y = (float)((int32_t)(yw) >> 8) * fixed_point_fraction;
1613 vertex[vi].z = (float)((int32_t)(zw) >> 8) * fixed_point_fraction;
1614 vertex[vi].u = (uint16_t)(model[index] >> 16);
1615 vertex[vi].v = (uint16_t)(model[index++]);
1616 // vertex[vi].nx = normal[0] + ((float)((int8_t)(xw)) / 127.0f);
1617 // vertex[vi].ny = normal[1] + ((float)((int8_t)(yw)) / 127.0f);
1618 // vertex[vi].nz = normal[2] + ((float)((int8_t)(zw)) / 127.0f);
1619
1620 vertex[vi].nx = ((float)((int8_t)(xw)) / 127.0f);
1621 vertex[vi].ny = ((float)((int8_t)(yw)) / 127.0f);
1622 vertex[vi].nz = ((float)((int8_t)(zw)) / 127.0f);
1623 }
1624
1625 /* Copy current vertices as previous vertices */
1626 memcpy(prev_vertex, vertex, sizeof(m3_vertex) * 4);
1627
1628 if (header[1] & 0x2)
1629 {
1630 color = (header[4] >> 8) & 0xffffff;
1631 }
1632 else
1633 {
1634 int ci = (header[4] >> 8) & 0x7ff;
1635 color = m_polygon_ram[0x400 + ci];
1636 }
1637
1638 polygon_transparency = (header[6] & 0x800000) ? 32 : ((header[6] >> 18) & 0x1f);
1639
1640 /* transform polygon normal to view-space */
1641 sn[0] = (normal[0] * transform_matrix[0][0]) +
1642 (normal[1] * transform_matrix[0][1]) +
1643 (normal[2] * transform_matrix[0][2]);
1644 sn[1] = (normal[0] * transform_matrix[1][0]) +
1645 (normal[1] * transform_matrix[1][1]) +
1646 (normal[2] * transform_matrix[1][2]);
1647 sn[2] = (normal[0] * transform_matrix[2][0]) +
1648 (normal[1] * transform_matrix[2][1]) +
1649 (normal[2] * transform_matrix[2][2]);
1650
1651 // TODO: depth bias
1652 // transform and light vertices
1653 for (i = 0; i < num_vertices; i++)
1654 {
1655 VECTOR vect;
1656
1657 vect[0] = vertex[i].x;
1658 vect[1] = vertex[i].y;
1659 vect[2] = vertex[i].z;
1660 vect[3] = 1.0f;
1661
1662 // transform to projection space
1663 matrix_multiply_vector(vp_matrix, vect, &p[i]);
1664
1665 clip_vert[i].x = p[i][0];
1666 clip_vert[i].y = p[i][1];
1667 clip_vert[i].z = p[i][2];
1668 clip_vert[i].w = p[i][3];
1669
1670 clip_vert[i].p[0] = vertex[i].u * texture_coord_scale * 256.0f; // 8 bits of subtexel accuracy for bilinear filtering
1671 clip_vert[i].p[1] = vertex[i].v * texture_coord_scale * 256.0f;
1672
1673 // transform vertex normal
1674 VECTOR3 n;
1675 n[0] = (vertex[i].nx * transform_matrix[0][0]) +
1676 (vertex[i].ny * transform_matrix[0][1]) +
1677 (vertex[i].nz * transform_matrix[0][2]);
1678 n[1] = (vertex[i].nx * transform_matrix[1][0]) +
1679 (vertex[i].ny * transform_matrix[1][1]) +
1680 (vertex[i].nz * transform_matrix[1][2]);
1681 n[2] = (vertex[i].nx * transform_matrix[2][0]) +
1682 (vertex[i].ny * transform_matrix[2][1]) +
1683 (vertex[i].nz * transform_matrix[2][2]);
1684
1685 // lighting
1686 float intensity;
1687 if ((header[6] & 0x10000) == 0)
1688 {
1689 float dot = dot_product3(n, m_parallel_light);
1690
1691 if (header[1] & 0x10)
1692 dot = fabs(dot);
1693
1694 intensity = ((dot * m_parallel_light_intensity) + m_ambient_light_intensity) * 255.0f;
1695 if (intensity > 255.0f)
1696 {
1697 intensity = 255.0f;
1698 }
1699 if (intensity < 0.0f)
1700 {
1701 intensity = 0.0f;
1702 }
1703 }
1704 else
1705 {
1706 intensity = 255.0f;
1707 }
1708
1709 clip_vert[i].p[2] = intensity;
1710 }
1711
1712 /* clip against all edges of the view frustum */
1713 num_vertices = frustum_clip_all<float, 4>(clip_vert, num_vertices, clip_vert);
1714
1715 /* divide by W, transform to screen coords */
1716 for(i=0; i < num_vertices; i++)
1717 {
1718 float oow = 1.0f / clip_vert[i].w;
1719
1720 clip_vert[i].x *= oow;
1721 clip_vert[i].y *= oow;
1722 clip_vert[i].z *= oow;
1723 clip_vert[i].p[0] *= oow;
1724 clip_vert[i].p[1] *= oow;
1725
1726 clip_vert[i].x = (((clip_vert[i].x * 0.5f) + 0.5f) * m_viewport_width) + m_viewport_x;
1727 clip_vert[i].y = (((clip_vert[i].y * 0.5f) + 0.5f) * m_viewport_height) + m_viewport_y;
1728 clip_vert[i].z = (((clip_vert[i].z * 0.5f) + 0.5f) * (m_viewport_far - m_viewport_near)) + m_viewport_near;
1729 }
1730
1731 /* backface culling */
1732 if( (header[6] & 0x800000) && (!(header[1] & 0x0010)) )
1733 {
1734 if (sn[0]*clip_vert[0].x + sn[1]*clip_vert[0].y + sn[2]*clip_vert[0].z > 0)
1735 back_face = 1;
1736 else
1737 back_face = 0;
1738 }
1739 else
1740 {
1741 back_face = 0; //no culling for transparent or two-sided polygons
1742 }
1743
1744 back_face = 0;
1745
1746 if (!back_face)
1747 {
1748 bool colormod = false;
1749 cached_texture* texture;
1750
1751 if (header[6] & 0x0000400)
1752 {
1753 int tex_x = ((header[4] & 0x1f) << 1) | ((header[5] >> 7) & 0x1);
1754 int tex_y = (header[5] & 0x1f);
1755 int tex_width = ((header[3] >> 3) & 0x7);
1756 int tex_height = (header[3] & 0x7);
1757 int tex_format = (header[6] >> 7) & 0x7;
1758
1759 if (tex_format != 0 && tex_format != 7) // enable color modulation if this is not a color texture
1760 colormod = true;
1761
1762 if (tex_width >= 6 || tex_height >= 6) // srally2 poly ram has degenerate polys with 2k tex size (cpu bug or intended?)
1763 return;
1764
1765 texture = get_texture((header[4] & 0x40) ? 1 : 0, tex_x, tex_y, tex_width, tex_height, tex_format);
1766 }
1767 else
1768 {
1769 texture = nullptr;
1770 }
1771
1772 for (i=2; i < num_vertices; i++)
1773 {
1774 bool alpha = (header[6] & 0x1) || ((header[6] & 0x800000) == 0); // put to alpha buffer if there's any transparency involved
1775 m3_triangle* tri = push_triangle(alpha);
1776
1777 // bail out if tri buffer is maxed out (happens during harley boot)
1778 if (!tri)
1779 return;
1780
1781 memcpy(&tri->v[0], &clip_vert[0], sizeof(m3_clip_vertex));
1782 memcpy(&tri->v[1], &clip_vert[i-1], sizeof(m3_clip_vertex));
1783 memcpy(&tri->v[2], &clip_vert[i], sizeof(m3_clip_vertex));
1784
1785 tri->texture = texture;
1786 tri->transparency = polygon_transparency;
1787 tri->color = color;
1788
1789 tri->param = 0;
1790 tri->param |= (header[4] & 0x40) ? TRI_PARAM_TEXTURE_PAGE : 0;
1791 tri->param |= (header[6] & 0x00000400) ? TRI_PARAM_TEXTURE_ENABLE : 0;
1792 tri->param |= (header[2] & 0x2) ? TRI_PARAM_TEXTURE_MIRROR_U : 0;
1793 tri->param |= (header[2] & 0x1) ? TRI_PARAM_TEXTURE_MIRROR_V : 0;
1794 tri->param |= (header[6] & 0x80000000) ? TRI_PARAM_ALPHA_TEST : 0;
1795 tri->param |= (colormod) ? TRI_PARAM_COLOR_MOD : 0;
1796 }
1797 }
1798 }
1799 }
1800
1801
1802 /*****************************************************************************/
1803 /* display list parser */
1804
get_memory_pointer(uint32_t address)1805 uint32_t *model3_state::get_memory_pointer(uint32_t address)
1806 {
1807 if (address & 0x800000)
1808 {
1809 if (address >= 0x840000) {
1810 fatalerror("get_memory_pointer: invalid display list memory address %08X\n", address);
1811 }
1812 return &m_display_list_ram[address & 0x7fffff];
1813 }
1814 else
1815 {
1816 if (address >= 0x100000) {
1817 fatalerror("get_memory_pointer: invalid node ram address %08X\n", address);
1818 }
1819 return &m_culling_ram[address];
1820 }
1821 }
1822
load_matrix(int matrix_num,MATRIX * out)1823 void model3_state::load_matrix(int matrix_num, MATRIX *out)
1824 {
1825 float *matrix = (float *)get_memory_pointer(m_matrix_base_address + matrix_num * 12);
1826
1827 (*out)[0][0] = matrix[3]; (*out)[0][1] = matrix[6]; (*out)[0][2] = matrix[9]; (*out)[0][3] = 0.0f;
1828 (*out)[1][0] = matrix[4]; (*out)[1][1] = matrix[7]; (*out)[1][2] = matrix[10]; (*out)[1][3] = 0.0f;
1829 (*out)[2][0] = matrix[5]; (*out)[2][1] = matrix[8]; (*out)[2][2] = matrix[11]; (*out)[2][3] = 0.0f;
1830 (*out)[3][0] = matrix[0]; (*out)[3][1] = matrix[1]; (*out)[3][2] = matrix[2]; (*out)[3][3] = 1.0f;
1831 }
1832
traverse_list4(int lod_num,uint32_t address)1833 void model3_state::traverse_list4(int lod_num, uint32_t address)
1834 {
1835 /* does something with the LOD selection */
1836 uint32_t *list = get_memory_pointer(address);
1837 uint32_t link = list[0];
1838
1839 draw_model(link & 0xffffff);
1840 }
1841
traverse_list(uint32_t address)1842 void model3_state::traverse_list(uint32_t address)
1843 {
1844 uint32_t *list = get_memory_pointer(address);
1845 int list_ptr = 0;
1846
1847 if (m_list_depth > 2)
1848 return;
1849
1850 m_list_depth++;
1851
1852 /* find the end of the list */
1853 while (1)
1854 {
1855 address = list[list_ptr++];
1856 if (address & 0x02000000)
1857 break;
1858 if (address == 0 || (address >> 24) != 0)
1859 {
1860 list_ptr--;
1861 break;
1862 }
1863 }
1864
1865 /* walk it backwards */
1866 while (list_ptr > 0)
1867 {
1868 address = list[--list_ptr] & 0xffffff;
1869 if (address != 0 && address != 0x800800)
1870 //if (address != 0)
1871 draw_block(address);
1872 }
1873
1874 m_list_depth--;
1875 }
1876
process_link(uint32_t address,uint32_t link)1877 inline void model3_state::process_link(uint32_t address, uint32_t link)
1878 {
1879 if (link != 0 && link != 0x0fffffff && link != 0x00800800 && link != 0x01000000)
1880 {
1881 switch (link >> 24)
1882 {
1883 case 0x00: /* link to another node */
1884 draw_block(link & 0xffffff);
1885 break;
1886
1887 case 0x01:
1888 case 0x03: /* both of these link to models, is there any difference ? */
1889 draw_model(link & 0xffffff);
1890 break;
1891
1892 case 0x04: /* list of links */
1893 traverse_list(link & 0xffffff);
1894 break;
1895
1896 default:
1897 logerror("process_link %08X: link = %08X\n", address, link);
1898 break;
1899 }
1900 }
1901 }
1902
draw_block(uint32_t address)1903 void model3_state::draw_block(uint32_t address)
1904 {
1905 const uint32_t *node = get_memory_pointer(address);
1906 uint32_t link;
1907 int node_matrix;
1908 float x, y, z;
1909 MATRIX matrix;
1910 int offset;
1911
1912 offset = (m_step < 0x15) ? 2 : 0;
1913 link = node[7 - offset];
1914
1915 /* apply matrix and translation */
1916 node_matrix = node[3 - offset] & 0xfff;
1917 load_matrix(node_matrix, &matrix);
1918
1919 push_matrix_stack();
1920
1921 if (node[0] & 0x10)
1922 {
1923 x = *(float *)&node[4 - offset];
1924 y = *(float *)&node[5 - offset];
1925 z = *(float *)&node[6 - offset];
1926 translate_matrix_stack(x, y, z);
1927 }
1928 else if (node_matrix != 0)
1929 multiply_matrix_stack(matrix);
1930
1931 /* bit 0x08 of word 0 indicates a pointer list */
1932 if (node[0] & 0x08)
1933 traverse_list4((node[3 - offset] >> 12) & 0x7f, link & 0xffffff);
1934 else
1935 process_link(address, link);
1936
1937 pop_matrix_stack();
1938
1939 /* handle the second link */
1940 if ((node[0] & 0x7) != 0x6)
1941 {
1942 link = node[8 - offset];
1943 process_link(address, link);
1944 }
1945 }
1946
draw_viewport(int pri,uint32_t address)1947 void model3_state::draw_viewport(int pri, uint32_t address)
1948 {
1949 const uint32_t *node = get_memory_pointer(address);
1950 uint32_t link_address;
1951
1952 link_address = node[1];
1953
1954 /* traverse to the link node before drawing this viewport */
1955 /* check this is correct as this affects the rendering order */
1956 if (link_address != 0x01000000 && link_address != 0)
1957 draw_viewport(pri, link_address);
1958
1959 /* skip if this isn't the right priority */
1960 if (pri != ((node[0] >> 3) & 3))
1961 return;
1962
1963 /* set viewport parameters */
1964 m_viewport_x = (float)(node[26] & 0xffff) / 16.0f; /* 12.4 fixed point */
1965 m_viewport_y = (float)((node[26] >> 16) & 0xffff) / 16.0f;
1966 m_viewport_width = (float)(node[20] & 0xffff) / 4.0f; /* 14.2 fixed point */
1967 m_viewport_height = (float)((node[20] >> 16) & 0xffff) / 4.0f;
1968
1969 m_viewport_near = 1.0f;
1970 m_viewport_far = 100000.0f;
1971
1972 /* set up frustum */
1973 float frustum_left = atan2(*(float *)&node[12], *(float *)&node[13]);
1974 float frustum_right = -atan2(*(float *)&node[16], -*(float *)&node[17]);
1975 float frustum_top = atan2(*(float *)&node[14], *(float *)&node[15]);
1976 float frustum_bottom = -atan2(*(float *)&node[18], -*(float *)&node[19]);
1977 // float frustum_1 = atan2(*(float *)&node[9], *(float *)&node[8]);
1978 // float frustum_2 = atan2(*(float *)&node[11], *(float *)&node[10]);
1979
1980 /*
1981 printf("%f\n", *(float *)&node[3]);
1982 printf("0: %f, 1: %f, 2: %f, 3: %f\n", *(float *)&node[8], *(float *)&node[9], *(float *)&node[10], *(float *)&node[11]);
1983 printf("4: %f, 5: %f, 6: %f, 7: %f\n", *(float *)&node[12], *(float *)&node[13], *(float *)&node[14], *(float *)&node[15]);
1984 printf("8: %f, 9: %f, A: %f, B: %f\n", *(float *)&node[16], *(float *)&node[17], *(float *)&node[18], *(float *)&node[19]);
1985 printf("fl = %f, fr = %f, ft = %f, fb = %f\n", RADIAN_TO_DEGREE(frustum_left), RADIAN_TO_DEGREE(frustum_right), RADIAN_TO_DEGREE(frustum_top), RADIAN_TO_DEGREE(frustum_bottom));
1986 printf("f1 = %f, f2 = %f\n", RADIAN_TO_DEGREE(frustum_1), RADIAN_TO_DEGREE(frustum_2));
1987 */
1988
1989 set_projection(frustum_left, frustum_right, frustum_top, frustum_bottom, m_viewport_near, m_viewport_far);
1990
1991
1992 m_matrix_base_address = node[22];
1993 /* TODO: where does node[23] point to ? LOD table ? */
1994
1995 /* set lighting parameters */
1996 m_parallel_light[0] = *(float *)&node[5];
1997 m_parallel_light[1] = *(float *)&node[6];
1998 m_parallel_light[2] = *(float *)&node[4];
1999 m_parallel_light_intensity = *(float *)&node[7];
2000 m_ambient_light_intensity = (uint8_t)(node[36] >> 8) / 256.0f;
2001
2002 /* set coordinate system matrix */
2003 load_matrix(0, &m_coordinate_system);
2004
2005 /* process a link */
2006 process_link(link_address, node[2]);
2007 }
2008
2009
real3d_traverse_display_list()2010 void model3_state::real3d_traverse_display_list()
2011 {
2012 init_matrix_stack();
2013
2014 m_list_depth = 0;
2015
2016 for (int pri = 0; pri < 4; pri++)
2017 {
2018 m_viewport_tri_index[pri] = m_tri_buffer_ptr;
2019 m_viewport_tri_alpha_index[pri] = m_tri_alpha_buffer_ptr;
2020 draw_viewport(pri, 0x800000);
2021 }
2022 }
2023
draw(bitmap_rgb32 & bitmap,const rectangle & cliprect)2024 void model3_renderer::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect)
2025 {
2026 for (int j = cliprect.min_y; j <= cliprect.max_y; ++j)
2027 {
2028 uint32_t *const dst = &bitmap.pix(j);
2029 uint32_t const *const src = &m_fb->pix(j);
2030
2031 for (int i = cliprect.min_x; i <= cliprect.max_x; ++i)
2032 {
2033 if (src[i] & 0xff000000)
2034 {
2035 dst[i] = src[i];
2036 }
2037 }
2038 }
2039 }
2040
clear_fb()2041 void model3_renderer::clear_fb()
2042 {
2043 rectangle cliprect;
2044 cliprect.min_x = 0;
2045 cliprect.min_y = 0;
2046 cliprect.max_x = 495;
2047 cliprect.max_y = 383;
2048
2049 m_fb->fill(0x00000000, cliprect);
2050 }
2051
clear_zb()2052 void model3_renderer::clear_zb()
2053 {
2054 rectangle cliprect;
2055 cliprect.min_x = 0;
2056 cliprect.min_y = 0;
2057 cliprect.max_x = 495;
2058 cliprect.max_y = 383;
2059
2060 float zvalue = 10000000000.0f;
2061 m_zb->fill(*(int*)&zvalue, cliprect);
2062 }
2063
wait_for_polys()2064 void model3_renderer::wait_for_polys()
2065 {
2066 wait();
2067 }
2068
draw_opaque_triangles(const m3_triangle * tris,int num_tris)2069 void model3_renderer::draw_opaque_triangles(const m3_triangle* tris, int num_tris)
2070 {
2071 rectangle cliprect;
2072 cliprect.min_x = 0;
2073 cliprect.min_y = 0;
2074 cliprect.max_x = 495;
2075 cliprect.max_y = 383;
2076
2077 // printf("draw opaque: %d\n", num_tris);
2078
2079 vertex_t v[3];
2080
2081 for (int t=0; t < num_tris; t++)
2082 {
2083 const m3_triangle* tri = &tris[t];
2084
2085 if (tri->param & TRI_PARAM_TEXTURE_ENABLE)
2086 {
2087 for (int i=0; i < 3; i++)
2088 {
2089 v[i].x = tri->v[i].x;
2090 v[i].y = tri->v[i].y;
2091 v[i].p[0] = tri->v[i].w;
2092 v[i].p[1] = 1.0f / tri->v[i].w;
2093 v[i].p[2] = tri->v[i].p[0];
2094 v[i].p[3] = tri->v[i].p[1];
2095 v[i].p[4] = tri->v[i].p[2];
2096 }
2097
2098 model3_polydata &extra = object_data_alloc();
2099 extra.texture = tri->texture;
2100 extra.transparency = tri->transparency;
2101 extra.texture_param = tri->param;
2102 extra.color = tri->color;
2103
2104 if (tri->param & TRI_PARAM_ALPHA_TEST)
2105 {
2106 render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_contour, this), 5, v[0], v[1], v[2]);
2107 }
2108 else
2109 {
2110 if (tri->param & TRI_PARAM_COLOR_MOD)
2111 render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_colormod, this), 5, v[0], v[1], v[2]);
2112 else
2113 render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex, this), 5, v[0], v[1], v[2]);
2114 }
2115 }
2116 else
2117 {
2118 for (int i=0; i < 3; i++)
2119 {
2120 v[i].x = tri->v[i].x;
2121 v[i].y = tri->v[i].y;
2122 v[i].p[0] = tri->v[i].w;
2123 v[i].p[1] = tri->v[i].p[2];
2124 }
2125
2126 model3_polydata &extra = object_data_alloc();
2127 extra.color = tri->color;
2128
2129 render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_solid, this), 2, v[0], v[1], v[2]);
2130 }
2131 }
2132 }
2133
draw_alpha_triangles(const m3_triangle * tris,int num_tris)2134 void model3_renderer::draw_alpha_triangles(const m3_triangle* tris, int num_tris)
2135 {
2136 rectangle cliprect;
2137 cliprect.min_x = 0;
2138 cliprect.min_y = 0;
2139 cliprect.max_x = 495;
2140 cliprect.max_y = 383;
2141
2142 // printf("draw alpha: %d\n", num_tris);
2143
2144 vertex_t v[3];
2145
2146 for (int t=num_tris-1; t >= 0; t--)
2147 {
2148 const m3_triangle* tri = &tris[t];
2149
2150 if (tri->param & TRI_PARAM_TEXTURE_ENABLE)
2151 {
2152 for (int i=0; i < 3; i++)
2153 {
2154 v[i].x = tri->v[i].x;
2155 v[i].y = tri->v[i].y;
2156 v[i].p[0] = tri->v[i].w;
2157 v[i].p[1] = 1.0f / tri->v[i].w;
2158 v[i].p[2] = tri->v[i].p[0];
2159 v[i].p[3] = tri->v[i].p[1];
2160 v[i].p[4] = tri->v[i].p[2];
2161 }
2162
2163 model3_polydata &extra = object_data_alloc();
2164 extra.texture = tri->texture;
2165 extra.transparency = tri->transparency;
2166 extra.texture_param = tri->param;
2167
2168 render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_tex_alpha, this), 5, v[0], v[1], v[2]);
2169 }
2170 else
2171 {
2172 for (int i=0; i < 3; i++)
2173 {
2174 v[i].x = tri->v[i].x;
2175 v[i].y = tri->v[i].y;
2176 v[i].p[0] = tri->v[i].w;
2177 v[i].p[1] = tri->v[i].p[2];
2178 }
2179
2180 model3_polydata &extra = object_data_alloc();
2181 extra.color = tri->color;
2182 extra.transparency = tri->transparency;
2183
2184 render_triangle(cliprect, render_delegate(&model3_renderer::draw_scanline_solid_trans, this), 2, v[0], v[1], v[2]);
2185 }
2186 }
2187 }
2188
draw_scanline_solid(int32_t scanline,const extent_t & extent,const model3_polydata & polydata,int threadid)2189 void model3_renderer::draw_scanline_solid(int32_t scanline, const extent_t &extent, const model3_polydata &polydata, int threadid)
2190 {
2191 uint32_t *const fb = &m_fb->pix(scanline);
2192 float *const zb = (float*)&m_zb->pix(scanline);
2193
2194 float z = extent.param[0].start;
2195 float dz = extent.param[0].dpdx;
2196
2197 float in = extent.param[1].start;
2198 float inz = extent.param[1].dpdx;
2199
2200 rgbaint_t color(polydata.color);
2201
2202 for (int x = extent.startx; x < extent.stopx; x++)
2203 {
2204 if (z <= zb[x])
2205 {
2206 rgbaint_t c(color);
2207
2208 c.scale_imm_and_clamp((int)in);
2209
2210 fb[x] = 0xff000000 | c.to_rgba_clamp();
2211 zb[x] = z;
2212 }
2213
2214 in += inz;
2215 z += dz;
2216 }
2217 }
2218
draw_scanline_solid_trans(int32_t scanline,const extent_t & extent,const model3_polydata & polydata,int threadid)2219 void model3_renderer::draw_scanline_solid_trans(int32_t scanline, const extent_t &extent, const model3_polydata &polydata, int threadid)
2220 {
2221 uint32_t *const fb = &m_fb->pix(scanline);
2222 float *const zb = (float*)&m_zb->pix(scanline);
2223
2224 float z = extent.param[0].start;
2225 float dz = extent.param[0].dpdx;
2226
2227 float in = extent.param[1].start;
2228 float inz = extent.param[1].dpdx;
2229
2230 rgbaint_t color(polydata.color);
2231
2232 int trans = (polydata.transparency << 3) | (polydata.transparency >> 2);
2233
2234 for (int x = extent.startx; x < extent.stopx; x++)
2235 {
2236 if (z <= zb[x])
2237 {
2238 rgbaint_t c(color);
2239
2240 c.scale_imm_and_clamp((int)in);
2241
2242 if (trans != 0xff)
2243 {
2244 c.blend(rgbaint_t(fb[x]), trans);
2245 }
2246
2247 fb[x] = 0xff000000 | c.to_rgba_clamp();
2248 }
2249
2250 in += inz;
2251 z += dz;
2252 }
2253 }
2254
2255 #define TEX_FETCH_NOFILTER() \
2256 do { \
2257 float intz = 1.0f / ooz; \
2258 uint32_t u = uoz * intz; \
2259 uint32_t v = voz * intz; \
2260 uint32_t u1 = (u >> 8) & umask; \
2261 uint32_t v1 = (v >> 8) & vmask; \
2262 texel = texture->data[(v1 << width) + u1]; \
2263 } while(0);
2264
2265 #define TEX_FETCH_BILINEAR() \
2266 do { \
2267 float intz = 1.0f / ooz; \
2268 uint32_t u = uoz * intz; \
2269 uint32_t v = voz * intz; \
2270 uint32_t u1 = (u >> 8) & umask; \
2271 uint32_t v1 = (v >> 8) & vmask; \
2272 uint32_t u2 = (u1 + 1) & umask; \
2273 uint32_t v2 = (v1 + 1) & vmask; \
2274 uint32_t pix00 = texture->data[(v1 << width) + u1]; \
2275 uint32_t pix01 = texture->data[(v1 << width) + u2]; \
2276 uint32_t pix10 = texture->data[(v2 << width) + u1]; \
2277 uint32_t pix11 = texture->data[(v2 << width) + u2]; \
2278 texel = rgbaint_t::bilinear_filter(pix00, pix01, pix10, pix11, u, v); \
2279 } while(0);
2280
2281 #if ENABLE_BILINEAR
2282 #define TEX_FETCH() TEX_FETCH_BILINEAR()
2283 #else
2284 #define TEX_FETCH() TEX_FETCH_NOFILTER()
2285 #endif
2286
draw_scanline_tex(int32_t scanline,const extent_t & extent,const model3_polydata & polydata,int threadid)2287 void model3_renderer::draw_scanline_tex(int32_t scanline, const extent_t &extent, const model3_polydata &polydata, int threadid)
2288 {
2289 uint32_t *const fb = &m_fb->pix(scanline);
2290 float *const zb = (float*)&m_zb->pix(scanline);
2291 const cached_texture *texture = polydata.texture;
2292
2293 float z = extent.param[0].start;
2294 float dz = extent.param[0].dpdx;
2295 float ooz = extent.param[1].start;
2296 float dooz = extent.param[1].dpdx;
2297 float uoz = extent.param[2].start;
2298 float duoz = extent.param[2].dpdx;
2299 float voz = extent.param[3].start;
2300 float dvoz = extent.param[3].dpdx;
2301 float in = extent.param[4].start;
2302 float inz = extent.param[4].dpdx;
2303
2304 uint32_t umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
2305 uint32_t vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
2306 uint32_t width = 6 + texture->width;
2307
2308 for (int x = extent.startx; x < extent.stopx; x++)
2309 {
2310 if (z <= zb[x])
2311 {
2312 uint32_t texel;
2313 TEX_FETCH(); // TODO fetch rgbaint_t instead
2314
2315 rgbaint_t color(texel);
2316
2317 color.scale_imm_and_clamp((int)in);
2318
2319 fb[x] = 0xff000000 | color.to_rgba_clamp();
2320 zb[x] = z;
2321 }
2322
2323 ooz += dooz;
2324 uoz += duoz;
2325 voz += dvoz;
2326 in += inz;
2327 z += dz;
2328 }
2329 }
2330
draw_scanline_tex_colormod(int32_t scanline,const extent_t & extent,const model3_polydata & polydata,int threadid)2331 void model3_renderer::draw_scanline_tex_colormod(int32_t scanline, const extent_t &extent, const model3_polydata &polydata, int threadid)
2332 {
2333 uint32_t *const fb = &m_fb->pix(scanline);
2334 float *const zb = (float*)&m_zb->pix(scanline);
2335 const cached_texture *texture = polydata.texture;
2336
2337 float z = extent.param[0].start;
2338 float dz = extent.param[0].dpdx;
2339 float ooz = extent.param[1].start;
2340 float dooz = extent.param[1].dpdx;
2341 float uoz = extent.param[2].start;
2342 float duoz = extent.param[2].dpdx;
2343 float voz = extent.param[3].start;
2344 float dvoz = extent.param[3].dpdx;
2345 float in = extent.param[4].start;
2346 float inz = extent.param[4].dpdx;
2347
2348 uint32_t umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
2349 uint32_t vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
2350 uint32_t width = 6 + texture->width;
2351
2352 rgbaint_t polycolor(polydata.color);
2353
2354 for (int x = extent.startx; x < extent.stopx; x++)
2355 {
2356 if (z <= zb[x])
2357 {
2358 uint32_t texel;
2359 TEX_FETCH(); // TODO fetch rgbaint_t instead
2360
2361 rgbaint_t color(texel);
2362
2363 color.scale_and_clamp(polycolor);
2364 color.scale_imm_and_clamp((int)in);
2365
2366 fb[x] = 0xff000000 | color.to_rgba_clamp();
2367 zb[x] = z;
2368 }
2369
2370 ooz += dooz;
2371 uoz += duoz;
2372 voz += dvoz;
2373 in += inz;
2374 z += dz;
2375 }
2376 }
2377
draw_scanline_tex_contour(int32_t scanline,const extent_t & extent,const model3_polydata & polydata,int threadid)2378 void model3_renderer::draw_scanline_tex_contour(int32_t scanline, const extent_t &extent, const model3_polydata &polydata, int threadid)
2379 {
2380 uint32_t *const fb = &m_fb->pix(scanline);
2381 float *const zb = (float*)&m_zb->pix(scanline);
2382 const cached_texture *texture = polydata.texture;
2383
2384 float z = extent.param[0].start;
2385 float dz = extent.param[0].dpdx;
2386 float ooz = extent.param[1].start;
2387 float dooz = extent.param[1].dpdx;
2388 float uoz = extent.param[2].start;
2389 float duoz = extent.param[2].dpdx;
2390 float voz = extent.param[3].start;
2391 float dvoz = extent.param[3].dpdx;
2392 float in = extent.param[4].start;
2393 float inz = extent.param[4].dpdx;
2394
2395 uint32_t umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
2396 uint32_t vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
2397 uint32_t width = 6 + texture->width;
2398
2399 rgbaint_t polycolor(polydata.color);
2400
2401 for (int x = extent.startx; x < extent.stopx; x++)
2402 {
2403 if (z <= zb[x])
2404 {
2405 uint32_t texel;
2406 TEX_FETCH();
2407
2408 uint32_t fa = texel >> 24;
2409 if (fa >= 0xf8)
2410 {
2411 rgbaint_t color(texel);
2412
2413 color.scale_and_clamp(polycolor);
2414 color.scale_imm_and_clamp((int)in);
2415 color.blend(rgbaint_t(fb[x]), fa);
2416
2417 fb[x] = 0xff000000 | color.to_rgba_clamp();
2418 zb[x] = z;
2419 }
2420 }
2421
2422 ooz += dooz;
2423 uoz += duoz;
2424 voz += dvoz;
2425 in += inz;
2426 z += dz;
2427 }
2428 }
2429
draw_scanline_tex_trans(int32_t scanline,const extent_t & extent,const model3_polydata & polydata,int threadid)2430 void model3_renderer::draw_scanline_tex_trans(int32_t scanline, const extent_t &extent, const model3_polydata &polydata, int threadid)
2431 {
2432 uint32_t *const fb = &m_fb->pix(scanline);
2433 float *const zb = (float*)&m_zb->pix(scanline);
2434 const cached_texture *texture = polydata.texture;
2435
2436 float z = extent.param[0].start;
2437 float dz = extent.param[0].dpdx;
2438 float ooz = extent.param[1].start;
2439 float dooz = extent.param[1].dpdx;
2440 float uoz = extent.param[2].start;
2441 float duoz = extent.param[2].dpdx;
2442 float voz = extent.param[3].start;
2443 float dvoz = extent.param[3].dpdx;
2444 float in = extent.param[4].start;
2445 float inz = extent.param[4].dpdx;
2446
2447 int trans = (polydata.transparency << 3) | (polydata.transparency >> 2);
2448
2449 uint32_t umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
2450 uint32_t vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
2451 uint32_t width = 6 + texture->width;
2452
2453 rgbaint_t polycolor(polydata.color);
2454
2455 for (int x = extent.startx; x < extent.stopx; x++)
2456 {
2457 if (z <= zb[x])
2458 {
2459 uint32_t texel;
2460 TEX_FETCH();
2461
2462 rgbaint_t color(texel);
2463
2464 color.scale_and_clamp(polycolor);
2465 color.scale_imm_and_clamp((int)in);
2466 color.blend(rgbaint_t(fb[x]), trans);
2467
2468 fb[x] = 0xff000000 | color.to_rgba_clamp();
2469 }
2470
2471 ooz += dooz;
2472 uoz += duoz;
2473 voz += dvoz;
2474 in += inz;
2475 z += dz;
2476 }
2477 }
2478
draw_scanline_tex_alpha(int32_t scanline,const extent_t & extent,const model3_polydata & polydata,int threadid)2479 void model3_renderer::draw_scanline_tex_alpha(int32_t scanline, const extent_t &extent, const model3_polydata &polydata, int threadid)
2480 {
2481 uint32_t *const fb = &m_fb->pix(scanline);
2482 float *const zb = (float*)&m_zb->pix(scanline);
2483 const cached_texture *texture = polydata.texture;
2484
2485 float z = extent.param[0].start;
2486 float dz = extent.param[0].dpdx;
2487 float ooz = extent.param[1].start;
2488 float dooz = extent.param[1].dpdx;
2489 float uoz = extent.param[2].start;
2490 float duoz = extent.param[2].dpdx;
2491 float voz = extent.param[3].start;
2492 float dvoz = extent.param[3].dpdx;
2493 float in = extent.param[4].start;
2494 float inz = extent.param[4].dpdx;
2495
2496 // int srctrans = polydata.transparency;
2497 // int desttrans = 32 - polydata.transparency;
2498
2499 uint32_t umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1;
2500 uint32_t vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1;
2501 uint32_t width = 6 + texture->width;
2502
2503 for (int x = extent.startx; x < extent.stopx; x++)
2504 {
2505 if (z <= zb[x])
2506 {
2507 uint32_t texel;
2508 TEX_FETCH();
2509
2510 uint32_t fa = texel >> 24;
2511 if (fa != 0)
2512 {
2513 rgbaint_t color(texel);
2514
2515 color.scale_imm_and_clamp((int)in);
2516 color.blend(rgbaint_t(fb[x]), fa);
2517
2518 fb[x] = 0xff000000 | color.to_rgba_clamp();
2519 }
2520 }
2521
2522 ooz += dooz;
2523 uoz += duoz;
2524 voz += dvoz;
2525 in += inz;
2526 z += dz;
2527 }
2528 }
2529