From 9f08ffb34a704cf60f814eef6ffb75a108ed3ca4 Mon Sep 17 00:00:00 2001 From: Andrew Gardner Date: Wed, 16 Sep 2015 16:42:19 +0200 Subject: [PATCH 1/7] A suggestion for how and where to put global MAME frustum clipping functions for 3d polygons. --- src/devices/video/poly.h | 144 +++++++++++++++++++++++++++++++++++ src/mame/includes/model3.h | 12 +-- src/mame/video/model3.c | 151 ++++--------------------------------- 3 files changed, 160 insertions(+), 147 deletions(-) diff --git a/src/devices/video/poly.h b/src/devices/video/poly.h index 1a564a2092d..c0a825763b8 100644 --- a/src/devices/video/poly.h +++ b/src/devices/video/poly.h @@ -1172,4 +1172,148 @@ int poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::zclip_if_less(i return nextout - outv; } + +template +struct frustum_clip_vertex +{ + _BaseType x, y, z, w; // A 3d coordinate already transformed by a projection matrix + _BaseType p[_MaxParams]; // Additional parameters to clip +}; + + +template +int frustum_clip_w(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_vertices, frustum_clip_vertex<_BaseType, _MaxParams>* out) +{ + if (num_vertices <= 0) + return 0; + + const _BaseType W_PLANE = 0.000001f; + + frustum_clip_vertex<_BaseType, _MaxParams> clipv[10]; + int clip_verts = 0; + + int previ = num_vertices - 1; + + for (int i=0; i < num_vertices; i++) + { + int v1_side = (v[i].w < W_PLANE) ? -1 : 1; + int v2_side = (v[previ].w < W_PLANE) ? -1 : 1; + + if ((v1_side * v2_side) < 0) // edge goes through W plane + { + // insert vertex at intersection point + _BaseType wdiv = v[previ].w - v[i].w; + if (wdiv == 0.0f) // 0 edge means degenerate polygon + return 0; + + _BaseType t = fabs((W_PLANE - v[previ].w) / wdiv); + + clipv[clip_verts].x = v[previ].x + ((v[i].x - v[previ].x) * t); + clipv[clip_verts].y = v[previ].y + ((v[i].y - v[previ].y) * t); + clipv[clip_verts].z = v[previ].z + ((v[i].z - v[previ].z) * t); + clipv[clip_verts].w = v[previ].w + ((v[i].w - v[previ].w) * t); + + // Interpolate the rest of the parameters + for (int pi = 0; pi < _MaxParams; pi++) + clipv[clip_verts].p[pi] = v[previ].p[pi] + ((v[i].p[pi] - v[previ].p[pi]) * t); + + ++clip_verts; + } + if (v1_side > 0) // current point is inside + { + clipv[clip_verts] = v[i]; + ++clip_verts; + } + + previ = i; + } + + memcpy(&out[0], &clipv[0], sizeof(out[0]) * clip_verts); + return clip_verts; +} + + +template +int frustum_clip(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_vertices, frustum_clip_vertex<_BaseType, _MaxParams>* out, int axis, int sign) +{ + if (num_vertices <= 0) + return 0; + + frustum_clip_vertex<_BaseType, _MaxParams> clipv[10]; + int clip_verts = 0; + + int previ = num_vertices - 1; + + for (int i=0; i < num_vertices; i++) + { + int v1_side, v2_side; + _BaseType* v1a = (_BaseType*)&v[i]; + _BaseType* v2a = (_BaseType*)&v[previ]; + + _BaseType v1_axis, v2_axis; + + if (sign) // +axis + { + v1_axis = v1a[axis]; + v2_axis = v2a[axis]; + } + else // -axis + { + v1_axis = -v1a[axis]; + v2_axis = -v2a[axis]; + } + + v1_side = (v1_axis <= v[i].w) ? 1 : -1; + v2_side = (v2_axis <= v[previ].w) ? 1 : -1; + + if ((v1_side * v2_side) < 0) // edge goes through W plane + { + // insert vertex at intersection point + _BaseType wdiv = ((v[previ].w - v2_axis) - (v[i].w - v1_axis)); + + if (wdiv == 0.0f) // 0 edge means degenerate polygon + return 0; + + _BaseType t = fabs((v[previ].w - v2_axis) / wdiv); + + clipv[clip_verts].x = v[previ].x + ((v[i].x - v[previ].x) * t); + clipv[clip_verts].y = v[previ].y + ((v[i].y - v[previ].y) * t); + clipv[clip_verts].z = v[previ].z + ((v[i].z - v[previ].z) * t); + clipv[clip_verts].w = v[previ].w + ((v[i].w - v[previ].w) * t); + + // Interpolate the rest of the parameters + for (int pi = 0; pi < _MaxParams; pi++) + clipv[clip_verts].p[pi] = v[previ].p[pi] + ((v[i].p[pi] - v[previ].p[pi]) * t); + + ++clip_verts; + } + if (v1_side > 0) // current point is inside + { + clipv[clip_verts] = v[i]; + ++clip_verts; + } + + previ = i; + } + + memcpy(&out[0], &clipv[0], sizeof(out[0]) * clip_verts); + return clip_verts; +} + + +template +int frustum_clip_all(frustum_clip_vertex<_BaseType, _MaxParams>* clip_vert, int num_vertices, frustum_clip_vertex<_BaseType, _MaxParams>* out) +{ + num_vertices = frustum_clip_w(clip_vert, num_vertices, clip_vert); + num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 0, 0); // W <= -X + num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 0, 1); // W <= +X + num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 1, 0); // W <= -Y + num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 1, 1); // W <= +X + num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 2, 0); // W <= -Z + num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 2, 1); // W <= +Z + out = clip_vert; + return num_vertices; +} + + #endif // __POLY_H__ diff --git a/src/mame/includes/model3.h b/src/mame/includes/model3.h index 93bb278e424..8279930e1c5 100644 --- a/src/mame/includes/model3.h +++ b/src/mame/includes/model3.h @@ -34,17 +34,7 @@ struct m3_vertex float nz; }; -struct m3_clip_vertex -{ - float x; - float y; - float z; - float w; - float u; - float v; - float i; - float s; -}; +typedef frustum_clip_vertex m3_clip_vertex; struct m3_triangle { diff --git a/src/mame/video/model3.c b/src/mame/video/model3.c index 8e60a6e79e5..a9340181902 100644 --- a/src/mame/video/model3.c +++ b/src/mame/video/model3.c @@ -1,7 +1,6 @@ // license:BSD-3-Clause // copyright-holders:R. Belmont, Ville Linde #include "emu.h" -#include "video/poly.h" #include "video/rgbutil.h" #include "includes/model3.h" @@ -1433,120 +1432,6 @@ void model3_state::set_projection(float left, float right, float top, float bott /*****************************************************************************/ /* transformation and rasterizing */ -static int clip_w(const m3_clip_vertex* v, int num_vertices, m3_clip_vertex* out) -{ - if (num_vertices <= 0) - return 0; - - const float W_PLANE = 0.000001f; - - m3_clip_vertex clipv[10]; - int clip_verts = 0; - - int previ = num_vertices - 1; - - for (int i=0; i < num_vertices; i++) - { - int v1_side = (v[i].w < W_PLANE) ? -1 : 1; - int v2_side = (v[previ].w < W_PLANE) ? -1 : 1; - - if ((v1_side * v2_side) < 0) // edge goes through W plane - { - // insert vertex at intersection point - float wdiv = v[previ].w - v[i].w; - if (wdiv == 0.0f) // 0 edge means degenerate polygon - return 0; - - float t = fabs((W_PLANE - v[previ].w) / wdiv); - - clipv[clip_verts].x = v[previ].x + ((v[i].x - v[previ].x) * t); - clipv[clip_verts].y = v[previ].y + ((v[i].y - v[previ].y) * t); - clipv[clip_verts].z = v[previ].z + ((v[i].z - v[previ].z) * t); - clipv[clip_verts].w = v[previ].w + ((v[i].w - v[previ].w) * t); - clipv[clip_verts].u = v[previ].u + ((v[i].u - v[previ].u) * t); - clipv[clip_verts].v = v[previ].v + ((v[i].v - v[previ].v) * t); - clipv[clip_verts].i = v[previ].i + ((v[i].i - v[previ].i) * t); - clipv[clip_verts].s = v[previ].s + ((v[i].s - v[previ].s) * t); - ++clip_verts; - } - if (v1_side > 0) // current point is inside - { - clipv[clip_verts] = v[i]; - ++clip_verts; - } - - previ = i; - } - - memcpy(&out[0], &clipv[0], sizeof(out[0]) * clip_verts); - return clip_verts; -} - -static int clip(const m3_clip_vertex* v, int num_vertices, m3_clip_vertex* out, int axis, int sign) -{ - if (num_vertices <= 0) - return 0; - - m3_clip_vertex clipv[10]; - int clip_verts = 0; - - int previ = num_vertices - 1; - - for (int i=0; i < num_vertices; i++) - { - int v1_side, v2_side; - float* v1a = (float*)&v[i]; - float* v2a = (float*)&v[previ]; - - float v1_axis, v2_axis; - - if (sign) // +axis - { - v1_axis = v1a[axis]; - v2_axis = v2a[axis]; - } - else // -axis - { - v1_axis = -v1a[axis]; - v2_axis = -v2a[axis]; - } - - v1_side = (v1_axis <= v[i].w) ? 1 : -1; - v2_side = (v2_axis <= v[previ].w) ? 1 : -1; - - if ((v1_side * v2_side) < 0) // edge goes through W plane - { - // insert vertex at intersection point - float wdiv = ((v[previ].w - v2_axis) - (v[i].w - v1_axis)); - - if (wdiv == 0.0f) // 0 edge means degenerate polygon - return 0; - - float t = fabs((v[previ].w - v2_axis) / wdiv); - - clipv[clip_verts].x = v[previ].x + ((v[i].x - v[previ].x) * t); - clipv[clip_verts].y = v[previ].y + ((v[i].y - v[previ].y) * t); - clipv[clip_verts].z = v[previ].z + ((v[i].z - v[previ].z) * t); - clipv[clip_verts].w = v[previ].w + ((v[i].w - v[previ].w) * t); - clipv[clip_verts].u = v[previ].u + ((v[i].u - v[previ].u) * t); - clipv[clip_verts].v = v[previ].v + ((v[i].v - v[previ].v) * t); - clipv[clip_verts].i = v[previ].i + ((v[i].i - v[previ].i) * t); - clipv[clip_verts].s = v[previ].s + ((v[i].s - v[previ].s) * t); - ++clip_verts; - } - if (v1_side > 0) // current point is inside - { - clipv[clip_verts] = v[i]; - ++clip_verts; - } - - previ = i; - } - - memcpy(&out[0], &clipv[0], sizeof(out[0]) * clip_verts); - return clip_verts; -} - void model3_state::reset_triangle_buffers() { m_tri_buffer_ptr = 0; @@ -1728,8 +1613,8 @@ void model3_state::draw_model(UINT32 addr) clip_vert[i].z = p[i][2]; clip_vert[i].w = p[i][3]; - clip_vert[i].u = vertex[i].u * texture_coord_scale * 256.0f; // 8 bits of subtexel accuracy for bilinear filtering - clip_vert[i].v = vertex[i].v * texture_coord_scale * 256.0f; + clip_vert[i].p[0] = vertex[i].u * texture_coord_scale * 256.0f; // 8 bits of subtexel accuracy for bilinear filtering + clip_vert[i].p[1] = vertex[i].v * texture_coord_scale * 256.0f; // transform vertex normal VECTOR3 n; @@ -1767,17 +1652,11 @@ void model3_state::draw_model(UINT32 addr) intensity = 255.0f; } - clip_vert[i].i = intensity; + clip_vert[i].p[2] = intensity; } - /* clip against view frustum */ - num_vertices = clip_w(clip_vert, num_vertices, clip_vert); - num_vertices = clip(clip_vert, num_vertices, clip_vert, 0, 0); // W <= -X - num_vertices = clip(clip_vert, num_vertices, clip_vert, 0, 1); // W <= +X - num_vertices = clip(clip_vert, num_vertices, clip_vert, 1, 0); // W <= -Y - num_vertices = clip(clip_vert, num_vertices, clip_vert, 1, 1); // W <= +X - num_vertices = clip(clip_vert, num_vertices, clip_vert, 2, 0); // W <= -Z - num_vertices = clip(clip_vert, num_vertices, clip_vert, 2, 1); // W <= +Z + /* clip against all edges of the view frustum */ + num_vertices = frustum_clip_all(clip_vert, num_vertices, clip_vert); /* divide by W, transform to screen coords */ for(i=0; i < num_vertices; i++) @@ -1787,8 +1666,8 @@ void model3_state::draw_model(UINT32 addr) clip_vert[i].x *= oow; clip_vert[i].y *= oow; clip_vert[i].z *= oow; - clip_vert[i].u *= oow; - clip_vert[i].v *= oow; + clip_vert[i].p[0] *= oow; + clip_vert[i].p[1] *= oow; clip_vert[i].x = (((clip_vert[i].x * 0.5f) + 0.5f) * m_viewport_width) + m_viewport_x; clip_vert[i].y = (((clip_vert[i].y * 0.5f) + 0.5f) * m_viewport_height) + m_viewport_y; @@ -2159,9 +2038,9 @@ void model3_renderer::draw_opaque_triangles(const m3_triangle* tris, int num_tri v[i].y = tri->v[i].y; v[i].p[0] = tri->v[i].w; v[i].p[1] = 1.0f / tri->v[i].w; - v[i].p[2] = tri->v[i].u; - v[i].p[3] = tri->v[i].v; - v[i].p[4] = tri->v[i].i; + v[i].p[2] = tri->v[i].p[0]; + v[i].p[3] = tri->v[i].p[1]; + v[i].p[4] = tri->v[i].p[2]; } model3_polydata &extra = object_data_alloc(); @@ -2189,7 +2068,7 @@ void model3_renderer::draw_opaque_triangles(const m3_triangle* tris, int num_tri v[i].x = tri->v[i].x; v[i].y = tri->v[i].y; v[i].p[0] = tri->v[i].w; - v[i].p[1] = tri->v[i].i; + v[i].p[1] = tri->v[i].p[2]; } model3_polydata &extra = object_data_alloc(); @@ -2224,9 +2103,9 @@ void model3_renderer::draw_alpha_triangles(const m3_triangle* tris, int num_tris v[i].y = tri->v[i].y; v[i].p[0] = tri->v[i].w; v[i].p[1] = 1.0f / tri->v[i].w; - v[i].p[2] = tri->v[i].u; - v[i].p[3] = tri->v[i].v; - v[i].p[4] = tri->v[i].i; + v[i].p[2] = tri->v[i].p[0]; + v[i].p[3] = tri->v[i].p[1]; + v[i].p[4] = tri->v[i].p[2]; } model3_polydata &extra = object_data_alloc(); @@ -2243,7 +2122,7 @@ void model3_renderer::draw_alpha_triangles(const m3_triangle* tris, int num_tris v[i].x = tri->v[i].x; v[i].y = tri->v[i].y; v[i].p[0] = tri->v[i].w; - v[i].p[1] = tri->v[i].i; + v[i].p[1] = tri->v[i].p[2]; } model3_polydata &extra = object_data_alloc(); From f0635169d5fb22787c5f7d060763ea4ae76ba0f1 Mon Sep 17 00:00:00 2001 From: Andrew Gardner Date: Fri, 18 Sep 2015 07:50:40 +0200 Subject: [PATCH 2/7] Some simple hng64 3d source cleanups. --- src/mame/includes/hng64.h | 66 ++++---- src/mame/video/hng64.c | 2 +- src/mame/video/hng64_3d.c | 332 +++++++++++++++++++------------------- 3 files changed, 204 insertions(+), 196 deletions(-) diff --git a/src/mame/includes/hng64.h b/src/mame/includes/hng64.h index 3b8b3e0fd2e..de4af7264a8 100644 --- a/src/mame/includes/hng64.h +++ b/src/mame/includes/hng64.h @@ -127,7 +127,6 @@ private: }; - class hng64_state : public driver_device { public: @@ -173,9 +172,7 @@ public: required_shared_ptr m_videoregs; required_shared_ptr m_tcram; - /* 3D stuff */ UINT16* m_dl; - required_shared_ptr m_3dregs; required_shared_ptr m_3d_1; required_shared_ptr m_3d_2; @@ -193,8 +190,8 @@ public: UINT16 *m_soundram2; /* Communications stuff */ - UINT8 *m_com_op_base; - UINT8 *m_com_virtual_mem; + UINT8 *m_com_op_base; + UINT8 *m_com_virtual_mem; UINT8 m_com_shared[8]; INT32 m_dma_start; @@ -319,6 +316,22 @@ public: TIMER_DEVICE_CALLBACK_MEMBER(hng64_irq); void do_dma(address_space &space); + void hng64_mark_all_tiles_dirty(int tilemap); + void hng64_mark_tile_dirty(int tilemap, int tile_index); + void hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int tm); + + void hng64_tilemap_draw_roz_core(screen_device &screen, tilemap_t *tmap, const blit_parameters *blit, + UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, int wraparound); + + void hng64_tilemap_draw_roz(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, + UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, + int wraparound, UINT32 flags, UINT8 priority, hng64trans_t drawformat); + + void hng64_tilemap_draw_roz_primask(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, + UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, + int wraparound, UINT32 flags, UINT8 priority, UINT8 priority_mask, hng64trans_t drawformat); + + DECLARE_CUSTOM_INPUT_MEMBER(left_handle_r); DECLARE_CUSTOM_INPUT_MEMBER(right_handle_r); @@ -327,44 +340,34 @@ public: hng64_poly_renderer* m_poly_renderer; - void clear3d(); - TIMER_CALLBACK_MEMBER(hng64_3dfifo_processed); + TIMER_CALLBACK_MEMBER(hng64_3dfifo_processed); + UINT8 *m_texturerom; + UINT16* m_vertsrom; + int m_vertsrom_size; + std::vector m_polys; // HNG64_MAX_POLYGONS + + void clear3d(); void hng64_command3d(const UINT16* packet); void draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); void transition_control(bitmap_rgb32 &bitmap, const rectangle &cliprect); - void hng64_tilemap_draw_roz_core(screen_device &screen, tilemap_t *tmap, const blit_parameters *blit, - UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, int wraparound); - void hng64_drawtilemap(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, int tm); void setCameraTransformation(const UINT16* packet); void setLighting(const UINT16* packet); void set3dFlags(const UINT16* packet); void setCameraProjectionMatrix(const UINT16* packet); - void recoverPolygonBlock(const UINT16* packet, int* numPolys); - void hng64_mark_all_tiles_dirty(int tilemap); - void hng64_mark_tile_dirty(int tilemap, int tile_index); - - void hng64_tilemap_draw_roz(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, - int wraparound, UINT32 flags, UINT8 priority, hng64trans_t drawformat); - - void hng64_tilemap_draw_roz_primask(screen_device &screen, bitmap_rgb32 &dest, const rectangle &cliprect, tilemap_t *tmap, - UINT32 startx, UINT32 starty, int incxx, int incxy, int incyx, int incyy, - int wraparound, UINT32 flags, UINT8 priority, UINT8 priority_mask, hng64trans_t drawformat); - + void recoverPolygonBlock(const UINT16* packet, int& numPolys); void printPacket(const UINT16* packet, int hex); + float uToF(UINT16 input); void matmul4(float *product, const float *a, const float *b); void vecmatmul4(float *product, const float *a, const float *b); float vecDotProduct(const float *a, const float *b); void setIdentity(float *matrix); - float uToF(UINT16 input); void normalize(float* x); - int Inside(struct polyVert *v, int plane); - void Intersect(struct polyVert *input0, struct polyVert *input1, struct polyVert *output, int plane); - void performFrustumClip(struct polygon *p); - UINT8 *m_texturerom; - UINT16* m_vertsrom; - int m_vertsrom_size; + int Inside(polyVert *v, int plane); + void Intersect(polyVert *input0, polyVert *input1, polyVert *output, int plane); + void performFrustumClip(polygon *p); + + void reset_sound(); void reset_net(); @@ -397,7 +400,6 @@ public: DECLARE_WRITE16_MEMBER(main_sound_comms_w); DECLARE_READ16_MEMBER(sound_comms_r); DECLARE_WRITE16_MEMBER(sound_comms_w); - UINT16 main_latch[2],sound_latch[2]; - - std::vector polys;//(1024*5); + UINT16 main_latch[2]; + UINT16 sound_latch[2]; }; diff --git a/src/mame/video/hng64.c b/src/mame/video/hng64.c index 2c7505d655c..9b8e6e03720 100644 --- a/src/mame/video/hng64.c +++ b/src/mame/video/hng64.c @@ -1273,7 +1273,7 @@ void hng64_state::video_start() // 3d information m_dl = auto_alloc_array(machine(), UINT16, 0x200/2); - polys.resize(1024*5); + m_polys.resize(HNG64_MAX_POLYGONS); m_texturerom = memregion("textures")->base(); m_vertsrom = (UINT16*)memregion("verts")->base(); diff --git a/src/mame/video/hng64_3d.c b/src/mame/video/hng64_3d.c index b64f3361483..3527be57ee7 100644 --- a/src/mame/video/hng64_3d.c +++ b/src/mame/video/hng64_3d.c @@ -56,7 +56,7 @@ WRITE16_MEMBER(hng64_state::dl_w) -/* TODO: different param for both Samurai games, less FIFO to process? */ +// TODO: different param for both Samurai games, less FIFO to process? WRITE32_MEMBER(hng64_state::dl_upload_w) { // this is written after the game uploads 16 packets, each 32 bytes long (2x 16 words?) @@ -80,7 +80,7 @@ TIMER_CALLBACK_MEMBER(hng64_state::hng64_3dfifo_processed) } -/* Note: Samurai Shodown games never calls bit 1, so it can't be framebuffer clear. It also calls bit 3 at start-up, meaning unknown */ +// Note: Samurai Shodown games never calls bit 1, so it can't be framebuffer clear. It also calls bit 3 at start-up, meaning unknown WRITE32_MEMBER(hng64_state::dl_control_w) // This handles framebuffers { // printf("dl_control_w %08x %08x\n", data, mem_mask); @@ -299,7 +299,7 @@ void hng64_state::setCameraProjectionMatrix(const UINT16* packet) // Operation 0100 // Polygon rasterization. -void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) +void hng64_state::recoverPolygonBlock(const UINT16* packet, int& numPolys) { /*////////////// // PACKET FORMAT @@ -372,7 +372,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) float ndCoords[4]; // Normalized device coordinates/clipCoordinates (x/w, y/w, z/w) float windowCoords[4]; // Mapped ndCoordinates to screen space float cullRay[4]; - struct polygon lastPoly = { 0 }; + polygon lastPoly = { 0 }; const rectangle &visarea = m_screen->visible_area(); @@ -442,11 +442,10 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) size[2] = threeDPointer[9]; size[3] = threeDPointer[10]; - /* ???? [11]; Used. */ - - /* ???? [12]; Used. */ - /* ???? [13]; Used. */ - /* ???? [14]; Used. */ + // ???? [11]; Used. + // ???? [12]; Used. + // ???? [13]; Used. + // ???? [14]; Used. if (threeDPointer[15] != 0x0000) printf("ZOMG! 3dPointer[15] is non-zero!\n"); if (threeDPointer[16] != 0x0000) printf("ZOMG! 3dPointer[16] is non-zero!\n"); @@ -456,7 +455,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) if (threeDPointer[19] != 0x0000) printf("ZOMG! 3dPointer[19] is non-zero!\n"); if (threeDPointer[20] != 0x0000) printf("ZOMG! 3dPointer[20] is non-zero!\n"); - /* Concatenate the megaOffset with the addresses */ + // Concatenate the megaOffset with the addresses address[0] |= (megaOffset << 16); address[1] |= (megaOffset << 16); address[2] |= (megaOffset << 16); @@ -468,7 +467,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) //if (threeDPointer[14] & 0x0001) tdColor |= 0x0000ff00; //if (threeDPointer[14] & 0x0000) tdColor |= 0x000000ff; - /* For all 4 polygon chunks */ + // For all 4 polygon chunks for (int k = 0; k < 4; k++) { UINT16* chunkOffset = &threeDRoms[address[k] * 3]; @@ -502,37 +501,40 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) continue; } + // Syntactical simplification + polygon& currentPoly = m_polys[numPolys]; + // Debug - Colors polygons with certain flags bright blue! ajg - polys[*numPolys].debugColor = 0; - //polys[*numPolys].debugColor = tdColor; + currentPoly.debugColor = 0; + //currentPoly.debugColor = tdColor; // Debug - ajg //printf("%d (%08x) : %04x %04x %04x\n", k, address[k]*3*2, chunkOffset[0], chunkOffset[1], chunkOffset[2]); //break; // TEXTURE - /* There may be more than just high & low res texture types, so I'm keeping texType as a UINT8. */ - if (chunkOffset[1] & 0x1000) polys[*numPolys].texType = 0x1; - else polys[*numPolys].texType = 0x0; + // There may be more than just high & low res texture types, so I'm keeping texType as a UINT8. */ + if (chunkOffset[1] & 0x1000) currentPoly.texType = 0x1; + else currentPoly.texType = 0x0; - polys[*numPolys].texPageSmall = (chunkOffset[2] & 0xc000)>>14; // Just a guess. - polys[*numPolys].texPageHorizOffset = (chunkOffset[2] & 0x3800) >> 11; - polys[*numPolys].texPageVertOffset = (chunkOffset[2] & 0x0070) >> 4; + currentPoly.texPageSmall = (chunkOffset[2] & 0xc000)>>14; // Just a guess. + currentPoly.texPageHorizOffset = (chunkOffset[2] & 0x3800) >> 11; + currentPoly.texPageVertOffset = (chunkOffset[2] & 0x0070) >> 4; - polys[*numPolys].texIndex = chunkOffset[1] & 0x000f; + currentPoly.texIndex = chunkOffset[1] & 0x000f; // PALETTE - polys[*numPolys].palOffset = 0; - polys[*numPolys].palPageSize = 0x100; + currentPoly.palOffset = 0; + currentPoly.palPageSize = 0x100; - /* FIXME: This isn't correct. - Buriki & Xrally need this line. Roads Edge needs it removed. - So instead we're looking for a bit that is on for XRally & Buriki, but noone else. */ + // FIXME: This isn't correct. + // Buriki & Xrally need this line. Roads Edge needs it removed. + // So instead we're looking for a bit that is on for XRally & Buriki, but noone else. if (m_3dregs[0x00/4] & 0x2000) { if (strcmp(machine().basename(), "roadedge")) - polys[*numPolys].palOffset += 0x800; + currentPoly.palOffset += 0x800; } //UINT16 explicitPaletteValue0 = ((chunkOffset[?] & 0x????) >> ?) * 0x800; @@ -540,7 +542,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) UINT16 explicitPaletteValue2 = ((chunkOffset[1] & 0x00f0) >> 4) * 0x008; // The presence of 0x00f0 *probably* sets 0x10-sized palette addressing. - if (explicitPaletteValue2) polys[*numPolys].palPageSize = 0x10; + if (explicitPaletteValue2) currentPoly.palPageSize = 0x10; // Apply the dynamic palette offset if its flag is set, otherwise stick with the fixed one if ((packet[1] & 0x0100)) @@ -549,7 +551,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) explicitPaletteValue2 = 0; // This is probably hiding somewhere in operation 0011 } - polys[*numPolys].palOffset += (explicitPaletteValue1 + explicitPaletteValue2); + currentPoly.palOffset += (explicitPaletteValue1 + explicitPaletteValue2); #if 0 @@ -557,7 +559,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) { // if (chunkOffset[2] == 0xd870) { - polys[*numPolys].debugColor = 0xffff0000; + currentPoly.debugColor = 0xffff0000; printf("%d (%08x) : %04x %04x %04x\n", k, address[k] * 3 * 2, chunkOffset[0], chunkOffset[1], chunkOffset[2]); } } @@ -583,29 +585,29 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) case 0x0f: // 0000 1111 for (int m = 0; m < 3; m++) { - polys[*numPolys].vert[m].worldCoords[0] = uToF(chunkOffset[3 + (9*m)]); - polys[*numPolys].vert[m].worldCoords[1] = uToF(chunkOffset[4 + (9*m)]); - polys[*numPolys].vert[m].worldCoords[2] = uToF(chunkOffset[5 + (9*m)]); - polys[*numPolys].vert[m].worldCoords[3] = 1.0f; - polys[*numPolys].n = 3; + currentPoly.vert[m].worldCoords[0] = uToF(chunkOffset[3 + (9*m)]); + currentPoly.vert[m].worldCoords[1] = uToF(chunkOffset[4 + (9*m)]); + currentPoly.vert[m].worldCoords[2] = uToF(chunkOffset[5 + (9*m)]); + currentPoly.vert[m].worldCoords[3] = 1.0f; + currentPoly.n = 3; // chunkOffset[6 + (9*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select - polys[*numPolys].vert[m].texCoords[0] = uToF(chunkOffset[7 + (9*m)]); - polys[*numPolys].vert[m].texCoords[1] = uToF(chunkOffset[8 + (9*m)]); - polys[*numPolys].vert[m].texCoords[2] = 0.0f; - polys[*numPolys].vert[m].texCoords[3] = 1.0f; + currentPoly.vert[m].texCoords[0] = uToF(chunkOffset[7 + (9*m)]); + currentPoly.vert[m].texCoords[1] = uToF(chunkOffset[8 + (9*m)]); + currentPoly.vert[m].texCoords[2] = 0.0f; + currentPoly.vert[m].texCoords[3] = 1.0f; - polys[*numPolys].vert[m].normal[0] = uToF(chunkOffset[9 + (9*m)]); - polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[10 + (9*m)]); - polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[11 + (9*m)]); - polys[*numPolys].vert[m].normal[3] = 0.0f; + currentPoly.vert[m].normal[0] = uToF(chunkOffset[9 + (9*m)]); + currentPoly.vert[m].normal[1] = uToF(chunkOffset[10 + (9*m)]); + currentPoly.vert[m].normal[2] = uToF(chunkOffset[11 + (9*m)]); + currentPoly.vert[m].normal[3] = 0.0f; } // Redundantly called, but it works... - polys[*numPolys].faceNormal[0] = uToF(chunkOffset[30]); - polys[*numPolys].faceNormal[1] = uToF(chunkOffset[31]); - polys[*numPolys].faceNormal[2] = uToF(chunkOffset[32]); - polys[*numPolys].faceNormal[3] = 0.0f; + currentPoly.faceNormal[0] = uToF(chunkOffset[30]); + currentPoly.faceNormal[1] = uToF(chunkOffset[31]); + currentPoly.faceNormal[2] = uToF(chunkOffset[32]); + currentPoly.faceNormal[3] = 0.0f; chunkLength = 33; break; @@ -618,29 +620,29 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) case 0x2e: // 0010 1110 for (int m = 0; m < 3; m++) { - polys[*numPolys].vert[m].worldCoords[0] = uToF(chunkOffset[3 + (6*m)]); - polys[*numPolys].vert[m].worldCoords[1] = uToF(chunkOffset[4 + (6*m)]); - polys[*numPolys].vert[m].worldCoords[2] = uToF(chunkOffset[5 + (6*m)]); - polys[*numPolys].vert[m].worldCoords[3] = 1.0f; - polys[*numPolys].n = 3; + currentPoly.vert[m].worldCoords[0] = uToF(chunkOffset[3 + (6*m)]); + currentPoly.vert[m].worldCoords[1] = uToF(chunkOffset[4 + (6*m)]); + currentPoly.vert[m].worldCoords[2] = uToF(chunkOffset[5 + (6*m)]); + currentPoly.vert[m].worldCoords[3] = 1.0f; + currentPoly.n = 3; // chunkOffset[6 + (6*m)] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select - polys[*numPolys].vert[m].texCoords[0] = uToF(chunkOffset[7 + (6*m)]); - polys[*numPolys].vert[m].texCoords[1] = uToF(chunkOffset[8 + (6*m)]); - polys[*numPolys].vert[m].texCoords[2] = 0.0f; - polys[*numPolys].vert[m].texCoords[3] = 1.0f; + currentPoly.vert[m].texCoords[0] = uToF(chunkOffset[7 + (6*m)]); + currentPoly.vert[m].texCoords[1] = uToF(chunkOffset[8 + (6*m)]); + currentPoly.vert[m].texCoords[2] = 0.0f; + currentPoly.vert[m].texCoords[3] = 1.0f; - polys[*numPolys].vert[m].normal[0] = uToF(chunkOffset[21]); - polys[*numPolys].vert[m].normal[1] = uToF(chunkOffset[22]); - polys[*numPolys].vert[m].normal[2] = uToF(chunkOffset[23]); - polys[*numPolys].vert[m].normal[3] = 0.0f; + currentPoly.vert[m].normal[0] = uToF(chunkOffset[21]); + currentPoly.vert[m].normal[1] = uToF(chunkOffset[22]); + currentPoly.vert[m].normal[2] = uToF(chunkOffset[23]); + currentPoly.vert[m].normal[3] = 0.0f; } // Redundantly called, but it works... - polys[*numPolys].faceNormal[0] = polys[*numPolys].vert[2].normal[0]; - polys[*numPolys].faceNormal[1] = polys[*numPolys].vert[2].normal[1]; - polys[*numPolys].faceNormal[2] = polys[*numPolys].vert[2].normal[2]; - polys[*numPolys].faceNormal[3] = 0.0f; + currentPoly.faceNormal[0] = currentPoly.vert[2].normal[0]; + currentPoly.faceNormal[1] = currentPoly.vert[2].normal[1]; + currentPoly.faceNormal[2] = currentPoly.vert[2].normal[2]; + currentPoly.faceNormal[3] = 0.0f; chunkLength = 24; break; @@ -652,31 +654,31 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) case 0xd7: // 1101 0111 case 0xc7: // 1100 0111 // Copy over the proper vertices from the previous triangle... - memcpy(&polys[*numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert)); - memcpy(&polys[*numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert)); + memcpy(¤tPoly.vert[1], &lastPoly.vert[0], sizeof(polyVert)); + memcpy(¤tPoly.vert[2], &lastPoly.vert[2], sizeof(polyVert)); // Fill in the appropriate data... - polys[*numPolys].vert[0].worldCoords[0] = uToF(chunkOffset[3]); - polys[*numPolys].vert[0].worldCoords[1] = uToF(chunkOffset[4]); - polys[*numPolys].vert[0].worldCoords[2] = uToF(chunkOffset[5]); - polys[*numPolys].vert[0].worldCoords[3] = 1.0f; - polys[*numPolys].n = 3; + currentPoly.vert[0].worldCoords[0] = uToF(chunkOffset[3]); + currentPoly.vert[0].worldCoords[1] = uToF(chunkOffset[4]); + currentPoly.vert[0].worldCoords[2] = uToF(chunkOffset[5]); + currentPoly.vert[0].worldCoords[3] = 1.0f; + currentPoly.n = 3; // chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select - polys[*numPolys].vert[0].texCoords[0] = uToF(chunkOffset[7]); - polys[*numPolys].vert[0].texCoords[1] = uToF(chunkOffset[8]); - polys[*numPolys].vert[0].texCoords[2] = 0.0f; - polys[*numPolys].vert[0].texCoords[3] = 1.0f; + currentPoly.vert[0].texCoords[0] = uToF(chunkOffset[7]); + currentPoly.vert[0].texCoords[1] = uToF(chunkOffset[8]); + currentPoly.vert[0].texCoords[2] = 0.0f; + currentPoly.vert[0].texCoords[3] = 1.0f; - polys[*numPolys].vert[0].normal[0] = uToF(chunkOffset[9]); - polys[*numPolys].vert[0].normal[1] = uToF(chunkOffset[10]); - polys[*numPolys].vert[0].normal[2] = uToF(chunkOffset[11]); - polys[*numPolys].vert[0].normal[3] = 0.0f; + currentPoly.vert[0].normal[0] = uToF(chunkOffset[9]); + currentPoly.vert[0].normal[1] = uToF(chunkOffset[10]); + currentPoly.vert[0].normal[2] = uToF(chunkOffset[11]); + currentPoly.vert[0].normal[3] = 0.0f; - polys[*numPolys].faceNormal[0] = uToF(chunkOffset[12]); - polys[*numPolys].faceNormal[1] = uToF(chunkOffset[13]); - polys[*numPolys].faceNormal[2] = uToF(chunkOffset[14]); - polys[*numPolys].faceNormal[3] = 0.0f; + currentPoly.faceNormal[0] = uToF(chunkOffset[12]); + currentPoly.faceNormal[1] = uToF(chunkOffset[13]); + currentPoly.faceNormal[2] = uToF(chunkOffset[14]); + currentPoly.faceNormal[3] = 0.0f; chunkLength = 15; break; @@ -689,33 +691,33 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) case 0xc6: // 1100 0110 case 0xd6: // 1101 0110 // Copy over the proper vertices from the previous triangle... - memcpy(&polys[*numPolys].vert[1], &lastPoly.vert[0], sizeof(struct polyVert)); - memcpy(&polys[*numPolys].vert[2], &lastPoly.vert[2], sizeof(struct polyVert)); + memcpy(¤tPoly.vert[1], &lastPoly.vert[0], sizeof(polyVert)); + memcpy(¤tPoly.vert[2], &lastPoly.vert[2], sizeof(polyVert)); - polys[*numPolys].vert[0].worldCoords[0] = uToF(chunkOffset[3]); - polys[*numPolys].vert[0].worldCoords[1] = uToF(chunkOffset[4]); - polys[*numPolys].vert[0].worldCoords[2] = uToF(chunkOffset[5]); - polys[*numPolys].vert[0].worldCoords[3] = 1.0f; - polys[*numPolys].n = 3; + currentPoly.vert[0].worldCoords[0] = uToF(chunkOffset[3]); + currentPoly.vert[0].worldCoords[1] = uToF(chunkOffset[4]); + currentPoly.vert[0].worldCoords[2] = uToF(chunkOffset[5]); + currentPoly.vert[0].worldCoords[3] = 1.0f; + currentPoly.n = 3; // chunkOffset[6] is almost always 0080, but it's 0070 for the translucent globe in fatfurwa player select - polys[*numPolys].vert[0].texCoords[0] = uToF(chunkOffset[7]); - polys[*numPolys].vert[0].texCoords[1] = uToF(chunkOffset[8]); - polys[*numPolys].vert[0].texCoords[2] = 0.0f; - polys[*numPolys].vert[0].texCoords[3] = 1.0f; + currentPoly.vert[0].texCoords[0] = uToF(chunkOffset[7]); + currentPoly.vert[0].texCoords[1] = uToF(chunkOffset[8]); + currentPoly.vert[0].texCoords[2] = 0.0f; + currentPoly.vert[0].texCoords[3] = 1.0f; // This normal could be right, but I'm not entirely sure - there is no normal in the 18 bytes! - polys[*numPolys].vert[0].normal[0] = lastPoly.faceNormal[0]; - polys[*numPolys].vert[0].normal[1] = lastPoly.faceNormal[1]; - polys[*numPolys].vert[0].normal[2] = lastPoly.faceNormal[2]; - polys[*numPolys].vert[0].normal[3] = lastPoly.faceNormal[3]; + currentPoly.vert[0].normal[0] = lastPoly.faceNormal[0]; + currentPoly.vert[0].normal[1] = lastPoly.faceNormal[1]; + currentPoly.vert[0].normal[2] = lastPoly.faceNormal[2]; + currentPoly.vert[0].normal[3] = lastPoly.faceNormal[3]; - polys[*numPolys].faceNormal[0] = lastPoly.faceNormal[0]; - polys[*numPolys].faceNormal[1] = lastPoly.faceNormal[1]; - polys[*numPolys].faceNormal[2] = lastPoly.faceNormal[2]; - polys[*numPolys].faceNormal[3] = lastPoly.faceNormal[3]; + currentPoly.faceNormal[0] = lastPoly.faceNormal[0]; + currentPoly.faceNormal[1] = lastPoly.faceNormal[1]; + currentPoly.faceNormal[2] = lastPoly.faceNormal[2]; + currentPoly.faceNormal[3] = lastPoly.faceNormal[3]; - // TODO: I'm not reading 3 necessary words here (maybe face normal) !!! + // TODO: I'm not reading 3 necessary words here (maybe face normal) #if 0 // DEBUG @@ -738,17 +740,17 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) break; } - polys[*numPolys].visible = 1; + currentPoly.visible = 1; // Backup the last polygon (for triangle fans [strips?]) - memcpy(&lastPoly, &polys[*numPolys], sizeof(struct polygon)); + memcpy(&lastPoly, ¤tPoly, sizeof(polygon)); //////////////////////////////////// // Project and clip // //////////////////////////////////// // Perform the world transformations... - // !! Can eliminate this step with a matrix stack (maybe necessary?) !! + // TODO: We can eliminate this step with a matrix stack (maybe necessary?) setIdentity(m_modelViewMatrix); if (m_mcu_type != SAMSHO_MCU) { @@ -767,7 +769,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) for (int v = 0; v < 3; v++) { float transformedNormal[4]; - vecmatmul4(transformedNormal, objectMatrix, polys[*numPolys].vert[v].normal); + vecmatmul4(transformedNormal, objectMatrix, currentPoly.vert[v].normal); normalize(transformedNormal); normalize(m_lightVector); @@ -777,9 +779,9 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) intensity *= 128.0; // Maps intensity to the range [0.0, 2.0] if (intensity >= 255.0f) intensity = 255.0f; - polys[*numPolys].vert[v].light[0] = intensity; - polys[*numPolys].vert[v].light[1] = intensity; - polys[*numPolys].vert[v].light[2] = intensity; + currentPoly.vert[v].light[0] = intensity; + currentPoly.vert[v].light[1] = intensity; + currentPoly.vert[v].light[2] = intensity; } } else @@ -787,77 +789,78 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) // Just clear out the light values for (int v = 0; v < 3; v++) { - polys[*numPolys].vert[v].light[0] = 0; - polys[*numPolys].vert[v].light[1] = 0; - polys[*numPolys].vert[v].light[2] = 0; + currentPoly.vert[v].light[0] = 0; + currentPoly.vert[v].light[1] = 0; + currentPoly.vert[v].light[2] = 0; } } // BACKFACE CULL // - // EMPIRICAL EVIDENCE SEEMS TO SHOW THE HNG64 HARDWARE DOES NOT BACKFACE CULL // + // (empirical evidence seems to show the hng64 hardware does not backface cull) // #if 0 float cullRay[4]; float cullNorm[4]; // Cast a ray out of the camera towards the polygon's point in eyespace. - vecmatmul4(cullRay, modelViewMatrix, polys[*numPolys].vert[0].worldCoords); + vecmatmul4(cullRay, modelViewMatrix, currentPoly.vert[0].worldCoords); normalize(cullRay); + // Dot product that with the normal to see if you're negative... - vecmatmul4(cullNorm, modelViewMatrix, polys[*numPolys].faceNormal); - - float result = vecDotProduct(cullRay, cullNorm); - - if (result < 0.0f) - polys[*numPolys].visible = 1; + vecmatmul4(cullNorm, modelViewMatrix, currentPoly.faceNormal); + + const float backfaceCullResult = vecDotProduct(cullRay, cullNorm); + if (backfaceCullResult < 0.0f) + currentPoly.visible = 1; else - polys[*numPolys].visible = 0; + currentPoly.visible = 0; #endif // BEHIND-THE-CAMERA CULL // - vecmatmul4(cullRay, m_modelViewMatrix, polys[*numPolys].vert[0].worldCoords); + vecmatmul4(cullRay, m_modelViewMatrix, currentPoly.vert[0].worldCoords); if (cullRay[2] > 0.0f) // Camera is pointing down -Z { - polys[*numPolys].visible = 0; + currentPoly.visible = 0; } // TRANSFORM THE TRIANGLE INTO HOMOGENEOUS SCREEN SPACE // - if (polys[*numPolys].visible) + if (currentPoly.visible) { - for (int m = 0; m < polys[*numPolys].n; m++) + for (int m = 0; m < currentPoly.n; m++) { // Transform and project the vertex into pre-divided homogeneous coordinates... - vecmatmul4(eyeCoords, m_modelViewMatrix, polys[*numPolys].vert[m].worldCoords); - vecmatmul4(polys[*numPolys].vert[m].clipCoords, m_projectionMatrix, eyeCoords); + vecmatmul4(eyeCoords, m_modelViewMatrix, currentPoly.vert[m].worldCoords); + vecmatmul4(currentPoly.vert[m].clipCoords, m_projectionMatrix, eyeCoords); } - if (polys[*numPolys].visible) + if (currentPoly.visible) { // Clip the triangles to the view frustum... - performFrustumClip(&polys[*numPolys]); + performFrustumClip(¤tPoly); - for (int m = 0; m < polys[*numPolys].n; m++) + for (int m = 0; m < currentPoly.n; m++) { // Convert into normalized device coordinates... - ndCoords[0] = polys[*numPolys].vert[m].clipCoords[0] / polys[*numPolys].vert[m].clipCoords[3]; - ndCoords[1] = polys[*numPolys].vert[m].clipCoords[1] / polys[*numPolys].vert[m].clipCoords[3]; - ndCoords[2] = polys[*numPolys].vert[m].clipCoords[2] / polys[*numPolys].vert[m].clipCoords[3]; - ndCoords[3] = polys[*numPolys].vert[m].clipCoords[3]; + ndCoords[0] = currentPoly.vert[m].clipCoords[0] / currentPoly.vert[m].clipCoords[3]; + ndCoords[1] = currentPoly.vert[m].clipCoords[1] / currentPoly.vert[m].clipCoords[3]; + ndCoords[2] = currentPoly.vert[m].clipCoords[2] / currentPoly.vert[m].clipCoords[3]; + ndCoords[3] = currentPoly.vert[m].clipCoords[3]; // Final pixel values are garnered here : windowCoords[0] = (ndCoords[0]+1.0f) * ((float)(visarea.max_x) / 2.0f) + 0.0f; windowCoords[1] = (ndCoords[1]+1.0f) * ((float)(visarea.max_y) / 2.0f) + 0.0f; windowCoords[2] = (ndCoords[2]+1.0f) * 0.5f; - windowCoords[1] = (float)visarea.max_y - windowCoords[1]; // Flip Y + // Flip Y + windowCoords[1] = (float)visarea.max_y - windowCoords[1]; // Store the points in a list for later use... - polys[*numPolys].vert[m].clipCoords[0] = windowCoords[0]; - polys[*numPolys].vert[m].clipCoords[1] = windowCoords[1]; - polys[*numPolys].vert[m].clipCoords[2] = windowCoords[2]; - polys[*numPolys].vert[m].clipCoords[3] = ndCoords[3]; + currentPoly.vert[m].clipCoords[0] = windowCoords[0]; + currentPoly.vert[m].clipCoords[1] = windowCoords[1]; + currentPoly.vert[m].clipCoords[2] = windowCoords[2]; + currentPoly.vert[m].clipCoords[3] = ndCoords[3]; } } } @@ -865,15 +868,16 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int* numPolys) // Advance to the next polygon chunk... chunkOffset += chunkLength; - (*numPolys)++; + numPolys++; } } } // note 0x0102 packets are only 8 words, it appears they can be in either the upper or lower half of the 16 word packet. -// We currently only draw 0x0102 packets where both halves contain 0x0102 (2 calls), but this causes graphics to vanish in xrally because in some cases the 0x0102 packet only exists in the upper or lower half -// with another value (often 0x0000 - NOP) in the other. -// If we also treat (0x0000 - NOP) as 8 word instead of 16 so that we can access a 0x0102 in the 2nd half of the 16 word packet then we end up with other invalid packets in the 2nd half which should be ignored. +// We currently only draw 0x0102 packets where both halves contain 0x0102 (2 calls), but this causes graphics to vanish in +// xrally because in some cases the 0x0102 packet only exists in the upper or lower half with another value (often 0x0000 - NOP) in the other. +// If we also treat (0x0000 - NOP) as 8 word instead of 16 so that we can access a 0x0102 in the 2nd half of the 16 word packet +// then we end up with other invalid packets in the 2nd half which should be ignored. // This would suggest our processing if flawed in other ways, or there is something else to indicate packet length. void hng64_state::hng64_command3d(const UINT16* packet) @@ -912,7 +916,7 @@ void hng64_state::hng64_command3d(const UINT16* packet) if (packet[2] == 0x0003 && packet[3] == 0x8f37 && m_mcu_type == SHOOT_MCU) break; - recoverPolygonBlock(packet, &numPolys); + recoverPolygonBlock(packet, numPolys); break; case 0x0102: // Geometry with only translation @@ -932,7 +936,7 @@ void hng64_state::hng64_command3d(const UINT16* packet) miniPacket[7] = 0x7fff; miniPacket[11] = 0x7fff; miniPacket[15] = 0x7fff; - recoverPolygonBlock(miniPacket, &numPolys); + recoverPolygonBlock(miniPacket, numPolys); memset(miniPacket, 0, sizeof(UINT16)*16); for (int i = 0; i < 7; i++) miniPacket[i] = packet[i+8]; @@ -940,7 +944,7 @@ void hng64_state::hng64_command3d(const UINT16* packet) miniPacket[7] = 0x7fff; miniPacket[11] = 0x7fff; miniPacket[15] = 0x7fff; - recoverPolygonBlock(miniPacket, &numPolys); + recoverPolygonBlock(miniPacket, numPolys); break; case 0x1000: // Unknown: Some sort of global flags? @@ -956,12 +960,12 @@ void hng64_state::hng64_command3d(const UINT16* packet) break; } - /* If there are polygons, rasterize them into the display buffer */ + // If there are polygons, rasterize them into the display buffer for (int i = 0; i < numPolys; i++) { - if (polys[i].visible) + if (m_polys[i].visible) { - m_poly_renderer->drawShaded(&polys[i]); + m_poly_renderer->drawShaded(&m_polys[i]); } } m_poly_renderer->wait(); @@ -1004,11 +1008,12 @@ void hng64_state::clear3d() * */ + ///////////////////// // 3D UTILITY CODE // ///////////////////// -/* 4x4 matrix multiplication */ +// 4x4 matrix multiplication void hng64_state::matmul4(float *product, const float *a, const float *b) { int i; @@ -1026,7 +1031,7 @@ void hng64_state::matmul4(float *product, const float *a, const float *b) } } -/* vector by 4x4 matrix multiply */ +// vector by 4x4 matrix multiply void hng64_state::vecmatmul4(float *product, const float *a, const float *b) { const float& bi0 = b[0]; @@ -1082,12 +1087,11 @@ void hng64_state::normalize(float* x) } - /////////////////////////// // POLYGON CLIPPING CODE // /////////////////////////// -int hng64_state::Inside(struct polyVert *v, int plane) +int hng64_state::Inside(polyVert *v, int plane) { switch(plane) { @@ -1110,7 +1114,7 @@ int hng64_state::Inside(struct polyVert *v, int plane) return 0; } -void hng64_state::Intersect(struct polyVert *input0, struct polyVert *input1, struct polyVert *output, int plane) +void hng64_state::Intersect(polyVert *input0, polyVert *input1, polyVert *output, int plane) { float t = 0.0f; @@ -1163,12 +1167,9 @@ void hng64_state::Intersect(struct polyVert *input0, struct polyVert *input1, st Ol[2] = Il0[2] + (Il1[2] - Il0[2]) * t; } -////////////////////////////////////////////////////////////////////////// -// Clip against the volumes defined by the homogeneous clip coordinates // -////////////////////////////////////////////////////////////////////////// - -void hng64_state::performFrustumClip(struct polygon *p) +void hng64_state::performFrustumClip(polygon *p) { + // Clip against the volumes defined by the homogeneous clip coordinates polyVert *v0; polyVert *v1; polyVert *tv; @@ -1190,7 +1191,7 @@ void hng64_state::performFrustumClip(struct polygon *p) if (Inside(v0, j) && Inside(v1, j)) // Edge is completely inside the volume... { - memcpy(tv, v1, sizeof(struct polyVert)); + memcpy(tv, v1, sizeof(polyVert)); temp.n++; } else if (Inside(v0, j) && !Inside(v1, j)) // Edge goes from in to out... @@ -1201,7 +1202,7 @@ void hng64_state::performFrustumClip(struct polygon *p) else if (!Inside(v0, j) && Inside(v1, j)) // Edge goes from out to in... { Intersect(v0, v1, tv, j); - memcpy(&temp.vert[temp.n+1], v1, sizeof(struct polyVert)); + memcpy(&temp.vert[temp.n+1], v1, sizeof(polyVert)); temp.n+=2; } } @@ -1210,13 +1211,18 @@ void hng64_state::performFrustumClip(struct polygon *p) for (int i = 0; i < temp.n; i++) { - memcpy(&p->vert[i], &temp.vert[i], sizeof(struct polyVert)); + memcpy(&p->vert[i], &temp.vert[i], sizeof(polyVert)); } temp.n = 0; } } + +//////////////////////////////// +// POLYGON RASTERIZATION CODE // +//////////////////////////////// + void hng64_poly_renderer::render_scanline(INT32 scanline, const extent_t& extent, const hng64_poly_data& renderData, int threadid) { // Pull the parameters out of the extent structure @@ -1351,7 +1357,7 @@ void hng64_poly_renderer::render_scanline(INT32 scanline, const extent_t& extent } } -void hng64_poly_renderer::drawShaded(struct polygon *p) +void hng64_poly_renderer::drawShaded(polygon *p) { // Polygon information for the rasterizer hng64_poly_data rOptions; From a88d0519017c0ff071969b2ce7bdbf9b02195b76 Mon Sep 17 00:00:00 2001 From: Andrew Gardner Date: Wed, 23 Sep 2015 16:14:24 +0200 Subject: [PATCH 3/7] Fixed a silly bug in the poly.h clipping code. Converted the hng64 over to the poly.h universal clipping code. --- src/devices/video/poly.h | 14 +-- src/mame/includes/hng64.h | 12 +-- src/mame/video/hng64_3d.c | 196 +++++++++----------------------------- 3 files changed, 58 insertions(+), 164 deletions(-) diff --git a/src/devices/video/poly.h b/src/devices/video/poly.h index c0a825763b8..0ba401e0755 100644 --- a/src/devices/video/poly.h +++ b/src/devices/video/poly.h @@ -1304,13 +1304,13 @@ int frustum_clip(const frustum_clip_vertex<_BaseType, _MaxParams>* v, int num_ve template int frustum_clip_all(frustum_clip_vertex<_BaseType, _MaxParams>* clip_vert, int num_vertices, frustum_clip_vertex<_BaseType, _MaxParams>* out) { - num_vertices = frustum_clip_w(clip_vert, num_vertices, clip_vert); - num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 0, 0); // W <= -X - num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 0, 1); // W <= +X - num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 1, 0); // W <= -Y - num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 1, 1); // W <= +X - num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 2, 0); // W <= -Z - num_vertices = frustum_clip(clip_vert, num_vertices, clip_vert, 2, 1); // W <= +Z + num_vertices = frustum_clip_w<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert); + num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 0, 0); // W <= -X + num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 0, 1); // W <= +X + num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 1, 0); // W <= -Y + num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 1, 1); // W <= +X + num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 2, 0); // W <= -Z + num_vertices = frustum_clip<_BaseType, _MaxParams>(clip_vert, num_vertices, clip_vert, 2, 1); // W <= +Z out = clip_vert; return num_vertices; } diff --git a/src/mame/includes/hng64.h b/src/mame/includes/hng64.h index de4af7264a8..413f8e642e9 100644 --- a/src/mame/includes/hng64.h +++ b/src/mame/includes/hng64.h @@ -24,7 +24,7 @@ enum hng64trans_t struct blit_parameters { - bitmap_rgb32 * bitmap; + bitmap_rgb32 * bitmap; rectangle cliprect; UINT32 tilemap_priority_code; UINT8 mask; @@ -55,7 +55,7 @@ struct polyVert struct polygon { int n; // Number of sides - struct polyVert vert[10]; // Vertices (maximum number per polygon is 10 -> 3+6) + polyVert vert[10]; // Vertices (maximum number per polygon is 10 -> 3+6) float faceNormal[4]; // Normal of the face overall - for calculating visibility and flat-shading... int visible; // Polygon visibility in scene @@ -92,6 +92,8 @@ struct polygon const int HNG64_MAX_POLYGONS = 10000; +typedef frustum_clip_vertex hng64_clip_vertex; + struct hng64_poly_data { UINT8 texType; @@ -111,7 +113,7 @@ class hng64_poly_renderer : public poly_managervisible_area(); @@ -751,6 +747,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int& numPolys) //////////////////////////////////// // Perform the world transformations... // TODO: We can eliminate this step with a matrix stack (maybe necessary?) + // Note: fatfurwa's helicopter tracking in scene 3 of its intro shows one of these matrices isn't quite correct setIdentity(m_modelViewMatrix); if (m_mcu_type != SAMSHO_MCU) { @@ -818,6 +815,7 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int& numPolys) // BEHIND-THE-CAMERA CULL // + float cullRay[4]; vecmatmul4(cullRay, m_modelViewMatrix, currentPoly.vert[0].worldCoords); if (cullRay[2] > 0.0f) // Camera is pointing down -Z { @@ -828,27 +826,57 @@ void hng64_state::recoverPolygonBlock(const UINT16* packet, int& numPolys) // TRANSFORM THE TRIANGLE INTO HOMOGENEOUS SCREEN SPACE // if (currentPoly.visible) { + hng64_clip_vertex clipVerts[10]; + + // Transform and project each vertex into pre-divided homogeneous coordinates for (int m = 0; m < currentPoly.n; m++) { - // Transform and project the vertex into pre-divided homogeneous coordinates... + float eyeCoords[4]; // World coordinates transformed by the modelViewMatrix vecmatmul4(eyeCoords, m_modelViewMatrix, currentPoly.vert[m].worldCoords); vecmatmul4(currentPoly.vert[m].clipCoords, m_projectionMatrix, eyeCoords); + + clipVerts[m].x = currentPoly.vert[m].clipCoords[0]; + clipVerts[m].y = currentPoly.vert[m].clipCoords[1]; + clipVerts[m].z = currentPoly.vert[m].clipCoords[2]; + clipVerts[m].w = currentPoly.vert[m].clipCoords[3]; + clipVerts[m].p[0] = currentPoly.vert[m].texCoords[0]; + clipVerts[m].p[1] = currentPoly.vert[m].texCoords[1]; + clipVerts[m].p[2] = currentPoly.vert[m].light[0]; + clipVerts[m].p[3] = currentPoly.vert[m].light[1]; + clipVerts[m].p[4] = currentPoly.vert[m].light[2]; } if (currentPoly.visible) { - // Clip the triangles to the view frustum... - performFrustumClip(¤tPoly); + // Clip against all edges of the view frustum + int num_vertices = frustum_clip_all(clipVerts, currentPoly.n, clipVerts); + + // Copy the results of + currentPoly.n = num_vertices; + for (int m = 0; m < num_vertices; m++) + { + currentPoly.vert[m].clipCoords[0] = clipVerts[m].x; + currentPoly.vert[m].clipCoords[1] = clipVerts[m].y; + currentPoly.vert[m].clipCoords[2] = clipVerts[m].z; + currentPoly.vert[m].clipCoords[3] = clipVerts[m].w; + currentPoly.vert[m].texCoords[0] = clipVerts[m].p[0]; + currentPoly.vert[m].texCoords[1] = clipVerts[m].p[1]; + currentPoly.vert[m].light[0] = clipVerts[m].p[2]; + currentPoly.vert[m].light[1] = clipVerts[m].p[3]; + currentPoly.vert[m].light[2] = clipVerts[m].p[4]; + } for (int m = 0; m < currentPoly.n; m++) { // Convert into normalized device coordinates... + float ndCoords[4]; // Normalized device coordinates/clipCoordinates (x/w, y/w, z/w) ndCoords[0] = currentPoly.vert[m].clipCoords[0] / currentPoly.vert[m].clipCoords[3]; ndCoords[1] = currentPoly.vert[m].clipCoords[1] / currentPoly.vert[m].clipCoords[3]; ndCoords[2] = currentPoly.vert[m].clipCoords[2] / currentPoly.vert[m].clipCoords[3]; ndCoords[3] = currentPoly.vert[m].clipCoords[3]; // Final pixel values are garnered here : + float windowCoords[4]; // Mapped ndCoordinates to screen space windowCoords[0] = (ndCoords[0]+1.0f) * ((float)(visarea.max_x) / 2.0f) + 0.0f; windowCoords[1] = (ndCoords[1]+1.0f) * ((float)(visarea.max_y) / 2.0f) + 0.0f; windowCoords[2] = (ndCoords[2]+1.0f) * 0.5f; @@ -1087,138 +1115,6 @@ void hng64_state::normalize(float* x) } -/////////////////////////// -// POLYGON CLIPPING CODE // -/////////////////////////// - -int hng64_state::Inside(polyVert *v, int plane) -{ - switch(plane) - { - case HNG64_LEFT: - return (v->clipCoords[0] >= -v->clipCoords[3]) ? 1 : 0; - case HNG64_RIGHT: - return (v->clipCoords[0] <= v->clipCoords[3]) ? 1 : 0; - - case HNG64_TOP: - return (v->clipCoords[1] <= v->clipCoords[3]) ? 1 : 0; - case HNG64_BOTTOM: - return (v->clipCoords[1] >= -v->clipCoords[3]) ? 1 : 0; - - case HNG64_NEAR: - return (v->clipCoords[2] <= v->clipCoords[3]) ? 1 : 0; - case HNG64_FAR: - return (v->clipCoords[2] >= -v->clipCoords[3]) ? 1 : 0; - } - - return 0; -} - -void hng64_state::Intersect(polyVert *input0, polyVert *input1, polyVert *output, int plane) -{ - float t = 0.0f; - - float *Iv0 = input0->clipCoords; - float *Iv1 = input1->clipCoords; - float *Ov = output->clipCoords; - - float *It0 = input0->texCoords; - float *It1 = input1->texCoords; - float *Ot = output->texCoords; - - float *Il0 = input0->light; - float *Il1 = input1->light; - float *Ol = output->light; - - switch(plane) - { - case HNG64_LEFT: - t = (Iv0[0]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[0]+Iv0[0]); - break; - case HNG64_RIGHT: - t = (Iv0[0]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[0]+Iv0[0]); - break; - case HNG64_TOP: - t = (Iv0[1]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[1]+Iv0[1]); - break; - case HNG64_BOTTOM: - t = (Iv0[1]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[1]+Iv0[1]); - break; - case HNG64_NEAR: - t = (Iv0[2]-Iv0[3]) / (Iv1[3]-Iv0[3]-Iv1[2]+Iv0[2]); - break; - case HNG64_FAR: - t = (Iv0[2]+Iv0[3]) / (-Iv1[3]+Iv0[3]-Iv1[2]+Iv0[2]); - break; - } - - Ov[0] = Iv0[0] + (Iv1[0] - Iv0[0]) * t; - Ov[1] = Iv0[1] + (Iv1[1] - Iv0[1]) * t; - Ov[2] = Iv0[2] + (Iv1[2] - Iv0[2]) * t; - Ov[3] = Iv0[3] + (Iv1[3] - Iv0[3]) * t; - - Ot[0] = It0[0] + (It1[0] - It0[0]) * t; - Ot[1] = It0[1] + (It1[1] - It0[1]) * t; - Ot[2] = It0[2] + (It1[2] - It0[2]) * t; - Ot[3] = It0[3] + (It1[3] - It0[3]) * t; - - Ol[0] = Il0[0] + (Il1[0] - Il0[0]) * t; - Ol[1] = Il0[1] + (Il1[1] - Il0[1]) * t; - Ol[2] = Il0[2] + (Il1[2] - Il0[2]) * t; -} - -void hng64_state::performFrustumClip(polygon *p) -{ - // Clip against the volumes defined by the homogeneous clip coordinates - polyVert *v0; - polyVert *v1; - polyVert *tv; - - polygon temp; - temp.n = 0; - - // Skip near and far clipping planes ? - for (int j = 0; j <= HNG64_BOTTOM; j++) - { - for (int i = 0; i < p->n; i++) - { - int k = (i+1) % p->n; // Index of next vertex - - v0 = &p->vert[i]; - v1 = &p->vert[k]; - - tv = &temp.vert[temp.n]; - - if (Inside(v0, j) && Inside(v1, j)) // Edge is completely inside the volume... - { - memcpy(tv, v1, sizeof(polyVert)); - temp.n++; - } - else if (Inside(v0, j) && !Inside(v1, j)) // Edge goes from in to out... - { - Intersect(v0, v1, tv, j); - temp.n++; - } - else if (!Inside(v0, j) && Inside(v1, j)) // Edge goes from out to in... - { - Intersect(v0, v1, tv, j); - memcpy(&temp.vert[temp.n+1], v1, sizeof(polyVert)); - temp.n+=2; - } - } - - p->n = temp.n; - - for (int i = 0; i < temp.n; i++) - { - memcpy(&p->vert[i], &temp.vert[i], sizeof(polyVert)); - } - - temp.n = 0; - } -} - - //////////////////////////////// // POLYGON RASTERIZATION CODE // //////////////////////////////// @@ -1371,7 +1267,7 @@ void hng64_poly_renderer::drawShaded(polygon *p) rOptions.texPageVertOffset = p->texPageVertOffset; // The perspective-correct texture divide... - // NOTE: There is a very good chance the HNG64 hardware does not do perspective-correct texture-mapping - explore + // Note: There is a very good chance the HNG64 hardware does not do perspective-correct texture-mapping - explore for (int j = 0; j < p->n; j++) { p->vert[j].clipCoords[3] = 1.0f / p->vert[j].clipCoords[3]; From bf50a10a936966dacfab9dadee9066634380a57f Mon Sep 17 00:00:00 2001 From: Andrew Gardner Date: Mon, 28 Sep 2015 10:25:02 +0200 Subject: [PATCH 4/7] Spacing fix / commit branch test. --- src/mame/drivers/hng64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mame/drivers/hng64.c b/src/mame/drivers/hng64.c index eac68a52fb0..f69637fae1a 100644 --- a/src/mame/drivers/hng64.c +++ b/src/mame/drivers/hng64.c @@ -2004,7 +2004,7 @@ ROM_START( buriki ) ROM_END /* Bios */ -GAME( 1997, hng64, 0, hng64, hng64, hng64_state, hng64, ROT0, "SNK", "Hyper NeoGeo 64 Bios", MACHINE_NOT_WORKING|MACHINE_NO_SOUND|MACHINE_IS_BIOS_ROOT ) +GAME( 1997, hng64, 0, hng64, hng64, hng64_state, hng64, ROT0, "SNK", "Hyper NeoGeo 64 Bios", MACHINE_NOT_WORKING|MACHINE_NO_SOUND|MACHINE_IS_BIOS_ROOT ) /* Games */ GAME( 1997, roadedge, hng64, hng64, roadedge, hng64_state, hng64_race, ROT0, "SNK", "Roads Edge / Round Trip (rev.B)", MACHINE_NOT_WORKING|MACHINE_NO_SOUND ) /* 001 */ From 106b674acbef43dca13e3437e03cca0af4bd45c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Mon, 28 Sep 2015 10:47:56 +0200 Subject: [PATCH 5/7] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fe413c00873..a83e4a627fe 100644 --- a/README.md +++ b/README.md @@ -73,3 +73,4 @@ MAME source code should be viewed and edited with your editor set to use four sp Some parts of the code follow [GNU style](http://www.gnu.org/prep/standards/html_node/Formatting.html); some parts of the code follow [K&R style](https://en.wikipedia.org/wiki/Indent_style#K.26R_style) -- mostly depending on who wrote the original version. **Above all else, be consistent with what you modify, and keep whitespace changes to a minimum when modifying existing source.** For new code, the majority tends to prefer GNU style, so if you don't care much, use that. All contributors need to either add standard header for license info (on new files) or send us their wish under which of licenses they would like their code to be published under :[BSD-3-Clause](http://spdx.org/licenses/BSD-3-Clause), or for new files in mame/ or mess/, either the [BSD-3-Clause](http://spdx.org/licenses/BSD-3-Clause) license, the [LGPL-2.1+](http://spdx.org/licenses/LGPL-2.1+), or the [GPL-2.0+](http://spdx.org/licenses/GPL-2.0+). + From 31b86bd828e1b963816d06dfd2ebe8b6941d98fb Mon Sep 17 00:00:00 2001 From: Andrew Gardner Date: Wed, 30 Sep 2015 11:07:43 +0200 Subject: [PATCH 6/7] Converted Namco System 23 games to use new frustum clipping code. --- src/mame/drivers/namcos23.c | 88 +++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/src/mame/drivers/namcos23.c b/src/mame/drivers/namcos23.c index 2f6e351d971..ed64c44983a 100644 --- a/src/mame/drivers/namcos23.c +++ b/src/mame/drivers/namcos23.c @@ -1928,10 +1928,9 @@ void namcos23_state::render_project(poly_vertex &pv) // 640/(3.125/3.75) = 768 // 480/(2.34375/3.75) = 768 - float w = pv.p[0] ? 1/pv.p[0] : 0; - pv.x = 320 + 768*w*pv.x; - pv.y = 240 - 768*w*pv.y; - pv.p[0] = w; + pv.x = 320 + 768 * pv.x; + pv.y = 240 - 768 * pv.y; + pv.p[0] = 1.0f / pv.p[0]; } static UINT32 render_texture_lookup_nocache_point(running_machine &machine, const pen_t *pens, float x, float y) @@ -2034,22 +2033,72 @@ void namcos23_state::render_one_model(const namcos23_render_entry *re) namcos23_poly_entry *p = render.polys + render.poly_count; + // Should be unnecessary now that frustum clipping happens, but this still culls polys behind the camera p->vertex_count = render.polymgr->zclip_if_less(ne, pv, p->pv, 4, 0.001f); - + + // Project if you don't clip on the near plane if(p->vertex_count >= 3) { - for(int i=0; ivertex_count; i++) { - render_project(p->pv[i]); - float w = p->pv[i].p[0]; - p->pv[i].p[1] *= w; - p->pv[i].p[2] *= w; - p->pv[i].p[3] *= w; - } - p->zkey = 0.5f*(minz+maxz); - p->front = !(h & 0x00000001); - p->rd.machine = &machine(); - p->rd.texture_lookup = render_texture_lookup_nocache_point; - p->rd.pens = m_palette->pens() + (color << 8); - render.poly_count++; + // Project the eye points + frustum_clip_vertex clipVerts[10]; + for(int i=0; ivertex_count; i++) { + // A basic perspective transform + const float Z = p->pv[i].p[0]; + const float projX = p->pv[i].x / Z; + const float projY = p->pv[i].y / Z; + + const float near = 0.001f; + const float far = 1000.0f; + const float m22 = -(far / (far-near)); + const float m23 = -((far * near) / (far - near)); + const float projZ = -(Z * m22) + m23; + const float projW = Z; + + // Construct a frustum clipping vert from the NDCoords + clipVerts[i].x = projX; + clipVerts[i].y = projY; + clipVerts[i].z = projZ; + clipVerts[i].w = projW; + clipVerts[i].p[0] = p->pv[i].p[1]; + clipVerts[i].p[1] = p->pv[i].p[2]; + clipVerts[i].p[2] = p->pv[i].p[3]; + } + + // Clip against all edges of the view frustum + int num_vertices = frustum_clip_all(clipVerts, p->vertex_count, clipVerts); + + if (num_vertices != 0) + { + // Push the results back into the main vertices + for (int i=0; i < num_vertices; i++) + { + p->pv[i].x = clipVerts[i].x; + p->pv[i].y = clipVerts[i].y; + p->pv[i].p[0] = clipVerts[i].w; + p->pv[i].p[1] = clipVerts[i].p[0]; + p->pv[i].p[2] = clipVerts[i].p[1]; + p->pv[i].p[3] = clipVerts[i].p[2]; + } + p->vertex_count = num_vertices; + + // This is our poor-man's projection matrix + for(int i=0; ivertex_count; i++) + { + render_project(p->pv[i]); + + float w = p->pv[i].p[0]; + p->pv[i].p[1] *= w; + p->pv[i].p[2] *= w; + p->pv[i].p[3] *= w; + } + + // Compute an odd sorta'-Z thing that can situate the polygon wherever you want in Z-depth + p->zkey = 0.5f*(minz+maxz); + p->front = !(h & 0x00000001); + p->rd.machine = &machine(); + p->rd.texture_lookup = render_texture_lookup_nocache_point; + p->rd.pens = m_palette->pens() + (color << 8); + render.poly_count++; + } } if(type & 0x000010000) @@ -2087,12 +2136,15 @@ void namcos23_renderer::render_flush(bitmap_rgb32& bitmap) namcos23_render_data& extra = render.polymgr->object_data_alloc(); extra = p->rd; + // We should probably split the polygons into triangles ourselves to insure everything is being rendered properly if (p->vertex_count == 3) render_triangle(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv[0], p->pv[1], p->pv[2]); else if (p->vertex_count == 4) render_polygon<4>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv); else if (p->vertex_count == 5) render_polygon<5>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv); + else if (p->vertex_count == 6) + render_polygon<6>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv); } render.poly_count = 0; From 31a1c1c2212e00d56f17d1ab5469346464b1d042 Mon Sep 17 00:00:00 2001 From: Andrew Gardner Date: Thu, 1 Oct 2015 13:24:24 +0200 Subject: [PATCH 7/7] Introduce standard Z-buffer depth sorting to namcos23. (polyplay branch) --- src/mame/drivers/namcos23.c | 262 ++++++++++++++++++------------------ 1 file changed, 133 insertions(+), 129 deletions(-) diff --git a/src/mame/drivers/namcos23.c b/src/mame/drivers/namcos23.c index ed64c44983a..9d5b932e286 100644 --- a/src/mame/drivers/namcos23.c +++ b/src/mame/drivers/namcos23.c @@ -1291,17 +1291,19 @@ struct namcos23_render_data class namcos23_state; -class namcos23_renderer : public poly_manager +class namcos23_renderer : public poly_manager { public: - namcos23_renderer(namcos23_state &state); - - void render_flush(bitmap_rgb32& bitmap); - void render_scanline(INT32 scanline, const extent_t& extent, const namcos23_render_data& object, int threadid); - + namcos23_renderer(namcos23_state &state); + + void render_flush(bitmap_rgb32& bitmap); + void render_scanline(INT32 scanline, const extent_t& extent, const namcos23_render_data& object, int threadid); + float* zBuffer() { return m_zBuffer; } + private: - namcos23_state& m_state; - bitmap_rgb32 m_bitmap; + namcos23_state& m_state; + bitmap_rgb32 m_bitmap; + float* m_zBuffer; }; typedef namcos23_renderer::vertex_t poly_vertex; @@ -1309,7 +1311,6 @@ typedef namcos23_renderer::vertex_t poly_vertex; struct namcos23_poly_entry { namcos23_render_data rd; - float zkey; int front; int vertex_count; poly_vertex pv[16]; @@ -1361,13 +1362,12 @@ struct c404_t struct render_t { - namcos23_renderer *polymgr; + namcos23_renderer *polymgr; int cur; int poly_count; int count[2]; namcos23_render_entry entries[2][RENDER_MAX_ENTRIES]; namcos23_poly_entry polys[POLY_MAX_ENTRIES]; - namcos23_poly_entry *poly_order[POLY_MAX_ENTRIES]; }; class namcos23_state : public driver_device @@ -1584,10 +1584,13 @@ UINT16 namcos23_state::nthword(const UINT32 *pSource, int offs) ***************************************************************************/ namcos23_renderer::namcos23_renderer(namcos23_state &state) - : poly_manager(state.machine()), - m_state(state), - m_bitmap(state.m_screen->width(), state.m_screen->height()) -{} + : poly_manager(state.machine()), + m_state(state), + m_bitmap(state.m_screen->width(), state.m_screen->height()) +{ + const INT32 bufferSize = state.m_screen->visible_area().width() * state.m_screen->visible_area().height(); + m_zBuffer = auto_alloc_array(state.machine(), float, bufferSize); +} // 3D hardware, to throw at least in part in video/namcos23.c @@ -1883,27 +1886,38 @@ void namcos23_renderer::render_scanline(INT32 scanline, const extent_t& extent, { const namcos23_render_data& rd = object; - float w = extent.param[0].start; - float u = extent.param[1].start; - float v = extent.param[2].start; - float l = extent.param[3].start; - float dw = extent.param[0].dpdx; - float du = extent.param[1].dpdx; - float dv = extent.param[2].dpdx; - float dl = extent.param[3].dpdx; + float zz = extent.param[0].start; + float w = extent.param[1].start; + float u = extent.param[2].start; + float v = extent.param[3].start; + float l = extent.param[4].start; + float dz = extent.param[0].dpdx; + float dw = extent.param[1].dpdx; + float du = extent.param[2].dpdx; + float dv = extent.param[3].dpdx; + float dl = extent.param[4].dpdx; + UINT32 *img = &m_bitmap.pix32(scanline, extent.startx); - + float* zBuffer = &m_zBuffer[(scanline * m_state.m_screen->visible_area().width()) + extent.startx]; + for(int x = extent.startx; x < extent.stopx; x++) { - float z = w ? 1/w : 0; - UINT32 pcol = rd.texture_lookup(*rd.machine, rd.pens, u*z, v*z); - float ll = l*z; - *img = (light(pcol >> 16, ll) << 16) | (light(pcol >> 8, ll) << 8) | light(pcol, ll); - + if (zz < *zBuffer) + { + float z = w ? 1/w : 0; + UINT32 pcol = rd.texture_lookup(*rd.machine, rd.pens, u*z, v*z); + float ll = l*z; + *img = (light(pcol >> 16, ll) << 16) | (light(pcol >> 8, ll) << 8) | light(pcol, ll); + + *zBuffer = zz; + } + + zz += dz; w += dw; u += du; v += dv; l += dl; img++; + zBuffer++; } } @@ -1928,9 +1942,9 @@ void namcos23_state::render_project(poly_vertex &pv) // 640/(3.125/3.75) = 768 // 480/(2.34375/3.75) = 768 - pv.x = 320 + 768 * pv.x; - pv.y = 240 - 768 * pv.y; - pv.p[0] = 1.0f / pv.p[0]; + pv.x = 320 + 768 * pv.x; + pv.y = 240 - 768 * pv.y; + pv.p[1] = 1.0f / pv.p[1]; } static UINT32 render_texture_lookup_nocache_point(running_machine &machine, const pen_t *pens, float x, float y) @@ -2033,72 +2047,71 @@ void namcos23_state::render_one_model(const namcos23_render_entry *re) namcos23_poly_entry *p = render.polys + render.poly_count; - // Should be unnecessary now that frustum clipping happens, but this still culls polys behind the camera - p->vertex_count = render.polymgr->zclip_if_less(ne, pv, p->pv, 4, 0.001f); - - // Project if you don't clip on the near plane + // Should be unnecessary now that frustum clipping happens, but this still culls polys behind the camera + p->vertex_count = render.polymgr->zclip_if_less(ne, pv, p->pv, 5, 0.001f); + + // Project if you don't clip on the near plane if(p->vertex_count >= 3) { - // Project the eye points - frustum_clip_vertex clipVerts[10]; - for(int i=0; ivertex_count; i++) { - // A basic perspective transform - const float Z = p->pv[i].p[0]; - const float projX = p->pv[i].x / Z; - const float projY = p->pv[i].y / Z; - - const float near = 0.001f; - const float far = 1000.0f; - const float m22 = -(far / (far-near)); - const float m23 = -((far * near) / (far - near)); - const float projZ = -(Z * m22) + m23; - const float projW = Z; - - // Construct a frustum clipping vert from the NDCoords - clipVerts[i].x = projX; - clipVerts[i].y = projY; - clipVerts[i].z = projZ; - clipVerts[i].w = projW; - clipVerts[i].p[0] = p->pv[i].p[1]; - clipVerts[i].p[1] = p->pv[i].p[2]; - clipVerts[i].p[2] = p->pv[i].p[3]; - } + // Project the eye points + frustum_clip_vertex clipVerts[10]; + for(int i=0; ivertex_count; i++) { + // A basic perspective transform + const float Z = p->pv[i].p[0]; + const float projX = p->pv[i].x / Z; + const float projY = p->pv[i].y / Z; + + const float near = 0.001f; + const float far = 1000.0f; + const float m22 = -(far / (far-near)); + const float m23 = -((far * near) / (far - near)); + const float projZ = -(Z * m22) + m23; + + // Construct a frustum clipping vert from the NDCoords + clipVerts[i].x = projX; + clipVerts[i].y = projY; + clipVerts[i].z = projZ; + clipVerts[i].w = p->pv[i].p[0]; + clipVerts[i].p[0] = p->pv[i].p[1]; + clipVerts[i].p[1] = p->pv[i].p[2]; + clipVerts[i].p[2] = p->pv[i].p[3]; + } - // Clip against all edges of the view frustum - int num_vertices = frustum_clip_all(clipVerts, p->vertex_count, clipVerts); - - if (num_vertices != 0) - { - // Push the results back into the main vertices - for (int i=0; i < num_vertices; i++) - { - p->pv[i].x = clipVerts[i].x; - p->pv[i].y = clipVerts[i].y; - p->pv[i].p[0] = clipVerts[i].w; - p->pv[i].p[1] = clipVerts[i].p[0]; - p->pv[i].p[2] = clipVerts[i].p[1]; - p->pv[i].p[3] = clipVerts[i].p[2]; - } - p->vertex_count = num_vertices; - - // This is our poor-man's projection matrix - for(int i=0; ivertex_count; i++) - { - render_project(p->pv[i]); - - float w = p->pv[i].p[0]; - p->pv[i].p[1] *= w; - p->pv[i].p[2] *= w; - p->pv[i].p[3] *= w; - } - - // Compute an odd sorta'-Z thing that can situate the polygon wherever you want in Z-depth - p->zkey = 0.5f*(minz+maxz); - p->front = !(h & 0x00000001); - p->rd.machine = &machine(); - p->rd.texture_lookup = render_texture_lookup_nocache_point; - p->rd.pens = m_palette->pens() + (color << 8); - render.poly_count++; - } + // Clip against all edges of the view frustum + int num_vertices = frustum_clip_all(clipVerts, p->vertex_count, clipVerts); + + if (num_vertices != 0) + { + // Push the results back into the main vertices + for (int i=0; i < num_vertices; i++) + { + p->pv[i].x = clipVerts[i].x; + p->pv[i].y = clipVerts[i].y; + p->pv[i].p[0] = clipVerts[i].z; + p->pv[i].p[1] = clipVerts[i].w; + p->pv[i].p[2] = clipVerts[i].p[0]; + p->pv[i].p[3] = clipVerts[i].p[1]; + p->pv[i].p[4] = clipVerts[i].p[2]; + } + p->vertex_count = num_vertices; + + // This is our poor-man's projection matrix + for(int i=0; ivertex_count; i++) + { + render_project(p->pv[i]); + + const float w = p->pv[i].p[1]; + p->pv[i].p[2] *= w; + p->pv[i].p[3] *= w; + p->pv[i].p[4] *= w; + } + + // Compute an odd sorta'-Z thing that can situate the polygon wherever you want in Z-depth + p->front = !(h & 0x00000001); + p->rd.machine = &machine(); + p->rd.texture_lookup = render_texture_lookup_nocache_point; + p->rd.pens = m_palette->pens() + (color << 8); + render.poly_count++; + } } if(type & 0x000010000) @@ -2106,17 +2119,6 @@ void namcos23_state::render_one_model(const namcos23_render_entry *re) } } -static int render_poly_compare(const void *i1, const void *i2) -{ - const namcos23_poly_entry *p1 = *(const namcos23_poly_entry **)i1; - const namcos23_poly_entry *p2 = *(const namcos23_poly_entry **)i2; - - if(p1->front != p2->front) - return p1->front ? 1 : -1; - - return p1->zkey < p2->zkey ? 1 : p1->zkey > p2->zkey ? -1 : 0; -} - void namcos23_renderer::render_flush(bitmap_rgb32& bitmap) { render_t &render = m_state.m_render; @@ -2124,31 +2126,33 @@ void namcos23_renderer::render_flush(bitmap_rgb32& bitmap) if(!render.poly_count) return; - for(int i=0; iobject_data_alloc(); - extra = p->rd; - - // We should probably split the polygons into triangles ourselves to insure everything is being rendered properly - if (p->vertex_count == 3) - render_triangle(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv[0], p->pv[1], p->pv[2]); - else if (p->vertex_count == 4) - render_polygon<4>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv); - else if (p->vertex_count == 5) - render_polygon<5>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv); - else if (p->vertex_count == 6) - render_polygon<6>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 4, p->pv); + const namcos23_poly_entry *p = &render.polys[i]; + namcos23_render_data& extra = render.polymgr->object_data_alloc(); + extra = p->rd; + + // We should probably split the polygons into triangles ourselves to insure everything is being rendered properly + if (p->vertex_count == 3) + render_triangle(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 5, p->pv[0], p->pv[1], p->pv[2]); + else if (p->vertex_count == 4) + render_polygon<4>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 5, p->pv); + else if (p->vertex_count == 5) + render_polygon<5>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 5, p->pv); + else if (p->vertex_count == 6) + render_polygon<6>(scissor, render_delegate(FUNC(namcos23_renderer::render_scanline), this), 5, p->pv); } render.poly_count = 0; - - copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, scissor); + + copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, scissor); + + // Reset the buffers + for (int i = 0; i < (m_state.m_screen->visible_area().width())*(m_state.m_screen->visible_area().height()); i++) + { + m_zBuffer[i] = 1000.0f; // TODO: set to far clipping plane value + } + } void namcos23_state::render_run(bitmap_rgb32 &bitmap) @@ -2169,7 +2173,7 @@ void namcos23_state::render_run(bitmap_rgb32 &bitmap) re++; } render.polymgr->render_flush(bitmap); - render.polymgr->wait(); + render.polymgr->wait(); } @@ -2241,7 +2245,7 @@ VIDEO_START_MEMBER(namcos23_state,s23) m_bgtilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(namcos23_state::TextTilemapGetInfo),this), TILEMAP_SCAN_ROWS, 16, 16, 64, 64); m_bgtilemap->set_transparent_pen(0xf); m_bgtilemap->set_scrolldx(860, 860); - m_render.polymgr = auto_alloc(machine(), namcos23_renderer(*this)); + m_render.polymgr = auto_alloc(machine(), namcos23_renderer(*this)); }