From b4a1e047036f83546b84dfc2c59339d96265ecf1 Mon Sep 17 00:00:00 2001 From: Aaron Giles Date: Mon, 21 Nov 2011 18:23:01 +0000 Subject: [PATCH] Introduce polynew.h which is a modernized C++ version of the old poly.c. Cleaned up a lot of stuff and made some changes in preparation for the future. Converted gaelco3d and midvunit over to the new system. --- .gitattributes | 1 + src/emu/video/polynew.h | 1121 ++++++++++++++++++++++++++++++++++ src/mame/drivers/gaelco3d.c | 28 - src/mame/includes/gaelco3d.h | 47 +- src/mame/includes/midvunit.h | 30 +- src/mame/video/gaelco3d.c | 252 ++++---- src/mame/video/midvunit.c | 211 +++---- 7 files changed, 1402 insertions(+), 288 deletions(-) create mode 100644 src/emu/video/polynew.h diff --git a/.gitattributes b/.gitattributes index a2edff5528b..0c92d59021a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1332,6 +1332,7 @@ src/emu/video/pc_vga.c svneol=native#text/plain src/emu/video/pc_vga.h svneol=native#text/plain src/emu/video/poly.c svneol=native#text/plain src/emu/video/poly.h svneol=native#text/plain +src/emu/video/polynew.h svneol=native#text/plain src/emu/video/psx.c svneol=native#text/plain src/emu/video/psx.h svneol=native#text/plain src/emu/video/resnet.c svneol=native#text/plain diff --git a/src/emu/video/polynew.h b/src/emu/video/polynew.h new file mode 100644 index 00000000000..8ec5e7fe46f --- /dev/null +++ b/src/emu/video/polynew.h @@ -0,0 +1,1121 @@ +/*************************************************************************** + + poly.h + + New polygon helper routines. + +**************************************************************************** + + Pixel model: + + (0.0,0.0) (1.0,0.0) (2.0,0.0) (3.0,0.0) + +---------------+---------------+---------------+ + | | | | + | | | | + | (0.5,0.5) | (1.5,0.5) | (2.5,0.5) | + | * | * | * | + | | | | + | | | | + (0.0,1.0) (1.0,1.0) (2.0,1.0) (3.0,1.0) + +---------------+---------------+---------------+ + | | | | + | | | | + | (0.5,1.5) | (1.5,1.5) | (2.5,1.5) | + | * | * | * | + | | | | + | | | | + | | | | + +---------------+---------------+---------------+ + (0.0,2.0) (1.0,2.0) (2.0,2.0) (3.0,2.0) + +***************************************************************************/ + +#pragma once + +#ifndef __POLYNEW_H__ +#define __POLYNEW_H__ + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +// keep statistics +#define KEEP_STATISTICS 0 + +// turn this on to log the reasons for any long waits +#define LOG_WAITS 0 + +// number of profiling ticks before we consider a wait "long" +#define LOG_WAIT_THRESHOLD 1000 + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define POLYFLAG_INCLUDE_BOTTOM_EDGE 0x01 +#define POLYFLAG_INCLUDE_RIGHT_EDGE 0x02 +#define POLYFLAG_NO_WORK_QUEUE 0x04 + +#define SCANLINES_PER_BUCKET 8 +#define CACHE_LINE_SIZE 64 // this is a general guess +#define TOTAL_BUCKETS (512 / SCANLINES_PER_BUCKET) +#define UNITS_PER_POLY (100 / SCANLINES_PER_BUCKET) + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// poly_manager is a template class +template +class poly_manager +{ +public: + // each vertex has an X/Y coordinate and a set of parameters + struct vertex_t + { + vertex_t() { } + vertex_t(_BaseType _x, _BaseType _y) { x = _x; y = _y; } + + _BaseType x, y; // X, Y coordinates + _BaseType p[_MaxParams]; // interpolated parameters + }; + + // a single extent describes a span and a list of parameter extents + struct extent_t + { + INT16 startx, stopx; // starting (inclusive)/ending (exclusive) endpoints + struct + { + _BaseType start; // parameter value at start + _BaseType dpdx; // dp/dx relative to start + } param[_MaxParams]; + }; + + // delegate type for scanline callbacks + typedef delegate render_delegate; + + // construction/destruction + poly_manager(running_machine &machine, UINT8 flags = 0); + virtual ~poly_manager(); + + // getters + running_machine &machine() const { return m_machine; } + + // synchronization + void wait(const char *debug_reason = "general"); + + // object data allocators + _ObjectData &object_data_alloc(); + _ObjectData &object_data_last() const { return m_object.last(); } + + // tiles + UINT32 render_tile(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &v1, const vertex_t &v2); + + // triangles + UINT32 render_triangle(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &v1, const vertex_t &v2, const vertex_t &v3); + UINT32 render_triangle_fan(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v); + UINT32 render_triangle_strip(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v); + UINT32 render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents); + + // polygons + template + UINT32 render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v); + + // public helpers + int zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, _BaseType clipval); + +private: + // polygon_info describes a single polygon, which includes the poly_params + struct polygon_info + { + poly_manager * m_owner; // pointer back to the poly manager + _ObjectData * m_object; // object data pointer + render_delegate m_callback; // callback to handle a scanline's worth of work + }; + + // internal unit of work + struct work_unit + { + volatile UINT32 count_next; // number of scanlines and index of next item to process + polygon_info * polygon; // pointer to polygon + INT16 scanline; // starting scanline + UINT16 previtem; // index of previous item in the same bucket + #ifndef PTR64 + UINT32 dummy; // pad to 16 bytes + #endif + extent_t extent[SCANLINES_PER_BUCKET]; // array of scanline extents + }; + + // class for managing an array of items + template + class poly_array + { + // size of an item, rounded up to the cache line size + static const int k_itemsize = ((sizeof(_Type) + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE; + + public: + // construction + poly_array(running_machine &machine, poly_manager &manager) + : m_manager(manager), + m_base(auto_alloc_array_clear(machine, UINT8, k_itemsize * _Count)), + m_next(0), + m_max(0), + m_waits(0) { } + + // destruction + ~poly_array() { auto_free(m_manager.machine(), m_base); } + + // operators + _Type &operator[](int index) const { assert(index >= 0 && index < _Count); return *reinterpret_cast<_Type *>(m_base + index * k_itemsize); } + + // getters + int count() const { return m_next; } + int max() const { return m_max; } + int waits() const { return m_waits; } + int itemsize() const { return k_itemsize; } + int allocated() const { return _Count; } + int indexof(_Type &item) const { int result = (reinterpret_cast(&item) - m_base) / k_itemsize; assert(result >= 0 && result < _Count); return result; } + + // operations + void reset() { m_next = 0; } + _Type &next() { if (m_next > m_max) m_max = m_next; assert(m_next < _Count); return *new(m_base + m_next++ * k_itemsize) _Type; } + _Type &last() const { return (*this)[m_next - 1]; } + void wait_for_space(int count = 1) { while ((m_next + count) >= _Count) { m_waits++; m_manager.wait(""); } } + + private: + // internal state + poly_manager & m_manager; + UINT8 * m_base; + int m_next; + int m_max; + int m_waits; + }; + + // internal array types + typedef poly_array polygon_array; + typedef poly_array<_ObjectData, _MaxPolys + 1> objectdata_array; + typedef poly_array unit_array; + + // round in a cross-platform consistent manner + inline INT32 round_coordinate(_BaseType value) + { + INT32 result = poly_floor(value); + return result + (value - _BaseType(result) > _BaseType(0.5)); + } + + // internal helpers + polygon_info &polygon_alloc(int minx, int maxx, int miny, int maxy, render_delegate callback) + { + // wait for space in the polygon and unit arrays + m_polygon.wait_for_space(); + m_unit.wait_for_space((maxy - miny) / SCANLINES_PER_BUCKET + 2); + + // return and initialize the next one + polygon_info &polygon = m_polygon.next(); + polygon.m_owner = this; + polygon.m_object = &object_data_last(); + polygon.m_callback = callback; + return polygon; + } + + static void *work_item_callback(void *param, int threadid); + void presave() { wait("pre-save"); } + + // queue management + running_machine & m_machine; + osd_work_queue * m_queue; // work queue + + // arrays + polygon_array m_polygon; // array of polygons + objectdata_array m_object; // array of object data + unit_array m_unit; // array of work units + + // misc data + UINT8 m_flags; // flags + + // buckets + UINT16 m_unit_bucket[TOTAL_BUCKETS]; // buckets for tracking unit usage + + // statistics + UINT32 m_tiles; // number of tiles queued + UINT32 m_triangles; // number of triangles queued + UINT32 m_quads; // number of quads queued + UINT64 m_pixels; // number of pixels rendered +#if KEEP_STATISTICS + UINT32 m_conflicts[WORK_MAX_THREADS]; // number of conflicts found, per thread + UINT32 m_resolved[WORK_MAX_THREADS]; // number of conflicts resolved, per thread +#endif +}; + + +//------------------------------------------------- +// global helpers for float base types +//------------------------------------------------- + +inline float poly_floor(float x) { return floorf(x); } +inline float poly_abs(float x) { return fabsf(x); } +inline float poly_recip(float x) { return 1.0f / x; } + + +//------------------------------------------------- +// global helpers for double base types +//------------------------------------------------- + +inline double poly_floor(double x) { return floor(x); } +inline double poly_abs(double x) { return fabs(x); } +inline double poly_recip(double x) { return 1.0 / x; } + + +//------------------------------------------------- +// poly_manager - constructor +//------------------------------------------------- + +template +poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::poly_manager(running_machine &machine, UINT8 flags) + : m_machine(machine), + m_queue(NULL), + m_polygon(machine, *this), + m_object(machine, *this), + m_unit(machine, *this), + m_flags(flags), + m_triangles(0), + m_quads(0), + m_pixels(0) +{ +#if KEEP_STATISTICS + memset(m_conflicts, 0, sizeof(m_conflicts)); + memset(m_resolved, 0, sizeof(m_resolved)); +#endif + + // create the work queue + if (!(flags & POLYFLAG_NO_WORK_QUEUE)) + m_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ); + + // request a pre-save callback for synchronization + machine.save().register_presave(save_prepost_delegate(FUNC(poly_manager::presave), this)); +} + + +//------------------------------------------------- +// ~poly_manager - destructor +//------------------------------------------------- + +template +poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::~poly_manager() +{ +#if KEEP_STATISTICS +{ + // accumulate stats over the entire collection + int conflicts = 0, resolved = 0; + for (int i = 0; i < ARRAY_LENGTH(m_conflicts); i++) + { + conflicts += m_conflicts[i]; + resolved += m_resolved[i]; + } + + // output global stats + printf("Total triangles = %d\n", m_triangles); + printf("Total quads = %d\n", m_quads); + if (m_pixels > 1000000000) + printf("Total pixels = %d%09d\n", (UINT32)(m_pixels / 1000000000), (UINT32)(m_pixels % 1000000000)); + else + printf("Total pixels = %d\n", (UINT32)m_pixels); + + printf("Conflicts: %d resolved, %d total\n", resolved, conflicts); + printf("Units: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_unit.max(), m_unit.allocated(), m_unit.waits(), m_unit.itemsize(), m_unit.allocated() * m_unit.itemsize()); + printf("Polygons: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_polygon.max(), m_polygon.allocated(), m_polygon.waits(), m_polygon.itemsize(), m_polygon.allocated() * m_polygon.itemsize()); + printf("Object data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", m_object.max(), m_object.allocated(), m_object.waits(), m_object.itemsize(), m_object.allocated() * m_object.itemsize()); +} +#endif + + // free the work queue + if (m_queue != NULL) + osd_work_queue_free(m_queue); +} + + +//------------------------------------------------- +// work_item_callback - process a work item +//------------------------------------------------- + +template +void *poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::work_item_callback(void *param, int threadid) +{ + while (1) + { + work_unit &unit = *(work_unit *)param; + polygon_info &polygon = *unit.polygon; + int count = unit.count_next & 0xffff; + UINT32 orig_count_next; + + // if our previous item isn't done yet, enqueue this item to the end and proceed + if (unit.previtem != 0xffff) + { + work_unit &prevunit = polygon.m_owner->m_unit[unit.previtem]; + if (prevunit.count_next != 0) + { + UINT32 unitnum = polygon.m_owner->m_unit.indexof(unit); + UINT32 new_count_next; + + // attempt to atomically swap in this new value + do + { + orig_count_next = prevunit.count_next; + new_count_next = orig_count_next | (unitnum << 16); + } while (compare_exchange32((volatile INT32 *)&prevunit.count_next, orig_count_next, new_count_next) != orig_count_next); + +#if KEEP_STATISTICS + // track resolved conflicts + polygon.m_owner->m_conflicts[threadid]++; + if (orig_count_next != 0) + polygon.m_owner->m_resolved[threadid]++; +#endif + // if we succeeded, skip out early so we can do other work + if (orig_count_next != 0) + break; + } + } + + // iterate over extents + for (int curscan = 0; curscan < count; curscan++) + polygon.m_callback(unit.scanline + curscan, unit.extent[curscan], *polygon.m_object, threadid); + + // set our count to 0 and re-fetch the original count value + do + { + orig_count_next = unit.count_next; + } while (compare_exchange32((volatile INT32 *)&unit.count_next, orig_count_next, 0) != orig_count_next); + + // if we have no more work to do, do nothing + orig_count_next >>= 16; + if (orig_count_next == 0) + break; + param = &polygon.m_owner->m_unit[orig_count_next]; + } + return NULL; +} + + +//------------------------------------------------- +// wait - stall until all work is complete +//------------------------------------------------- + +template +void poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::wait(const char *debug_reason) +{ + osd_ticks_t time; + + // remember the start time if we're logging + if (LOG_WAITS) + time = get_profile_ticks(); + + // wait for all pending work items to complete + if (m_queue != NULL) + osd_work_queue_wait(m_queue, osd_ticks_per_second() * 100); + + // if we don't have a queue, just run the whole list now + else + for (int unitnum = 0; unitnum < m_unit.count(); unitnum++) + work_item_callback(&m_unit[unitnum], 0); + + // log any long waits + if (LOG_WAITS) + { + time = get_profile_ticks() - time; + if (time > LOG_WAIT_THRESHOLD) + logerror("Poly:Waited %d cycles for %s\n", (int)time, debug_reason); + } + + // reset the state + m_polygon.reset(); + m_unit.reset(); + memset(m_unit_bucket, 0xff, sizeof(m_unit_bucket)); + + // we need to preserve the last object data that was supplied + if (m_object.count() > 0) + { + _ObjectData temp = object_data_last(); + m_object.reset(); + m_object.next() = temp; + } + else + m_object.reset(); +} + + +//------------------------------------------------- +// object_data_alloc - allocate a new _ObjectData +//------------------------------------------------- + +template +_ObjectData &poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::object_data_alloc() +{ + // wait for a work item if we have to, then return the next item + m_object.wait_for_space(); + return m_object.next(); +} + + +//------------------------------------------------- +// render_tile - render a tile +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_tile(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2) +{ + const vertex_t *v1 = &_v1; + const vertex_t *v2 = &_v2; + + // first sort by Y + if (v2->y < v1->y) + { + const vertex_t *tv = v1; + v1 = v2; + v2 = tv; + } + + // compute some integral X/Y vertex values + INT32 v1y = round_coordinate(v1->y); + INT32 v2y = round_coordinate(v2->y); + + // clip coordinates + INT32 v1yclip = v1y; + INT32 v2yclip = v2y + ((m_flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + v1yclip = MAX(v1yclip, cliprect.min_y); + v2yclip = MIN(v2yclip, cliprect.max_y + 1); + if (v2yclip - v1yclip <= 0) + return 0; + + // determine total X extents + _BaseType minx = v1->x; + _BaseType maxx = v2->x; + if (minx > maxx) + return 0; + + // allocate and populate a new polygon + polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v2yclip, callback); + + // compute parameter deltas + _BaseType param_dpdx[_MaxParams]; + _BaseType param_dpdy[_MaxParams]; + if (paramcount > 0) + { + _BaseType oox = poly_recip(v2->x - v1->x); + _BaseType ooy = poly_recip(v2->y - v1->y); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + param_dpdx[paramnum] = oox * (v2->p[paramnum] - v1->p[paramnum]); + param_dpdy[paramnum] = ooy * (v2->p[paramnum] - v1->p[paramnum]); + } + } + + // clamp to full pixels + INT32 istartx = round_coordinate(v1->x); + INT32 istopx = round_coordinate(v2->x); + + // force start < stop + if (istartx > istopx) + { + INT32 temp = istartx; + istartx = istopx; + istopx = temp; + } + + // include the right edge if requested + if (m_flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + // apply left/right clipping + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + if (istartx >= istopx) + return 0; + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = v1yclip; curscan < v2yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(v2yclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + // compute the ending X based on which part of the triangle we're in + _BaseType fully = _BaseType(curscan + extnum) + _BaseType(0.5); + + // set the extent and update the total pixel count + extent_t &extent = unit.extent[extnum]; + extent.startx = istartx; + extent.stopx = istopx; + pixels += istopx - istartx; + + // fill in the parameters for the extent + _BaseType fullstartx = _BaseType(istartx) + _BaseType(0.5); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + extent.param[paramnum].start = v1->p[paramnum] + fullstartx * param_dpdx[paramnum] + fully * param_dpdy[paramnum]; + extent.param[paramnum].dpdx = param_dpdx[paramnum]; + } + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the triangle + m_tiles++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// render_triangle - render a single triangle +// given 3 vertexes +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t &_v1, const vertex_t &_v2, const vertex_t &_v3) +{ + const vertex_t *v1 = &_v1; + const vertex_t *v2 = &_v2; + const vertex_t *v3 = &_v3; + + // first sort by Y + if (v2->y < v1->y) + { + const vertex_t *tv = v1; + v1 = v2; + v2 = tv; + } + if (v3->y < v2->y) + { + const vertex_t *tv = v2; + v2 = v3; + v3 = tv; + if (v2->y < v1->y) + { + const vertex_t *tv = v1; + v1 = v2; + v2 = tv; + } + } + + // compute some integral X/Y vertex values + INT32 v1y = round_coordinate(v1->y); + INT32 v3y = round_coordinate(v3->y); + + // clip coordinates + INT32 v1yclip = v1y; + INT32 v3yclip = v3y + ((m_flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + v1yclip = MAX(v1yclip, cliprect.min_y); + v3yclip = MIN(v3yclip, cliprect.max_y + 1); + if (v3yclip - v1yclip <= 0) + return 0; + + // determine total X extents + _BaseType minx = v1->x; + _BaseType maxx = v1->x; + if (v2->x < minx) minx = v2->x; + else if (v2->x > maxx) maxx = v2->x; + if (v3->x < minx) minx = v3->x; + else if (v3->x > maxx) maxx = v3->x; + + // allocate and populate a new polygon + polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), v1yclip, v3yclip, callback); + + // compute the slopes for each portion of the triangle + _BaseType dxdy_v1v2 = (v2->y == v1->y) ? _BaseType(0.0) : (v2->x - v1->x) / (v2->y - v1->y); + _BaseType dxdy_v1v3 = (v3->y == v1->y) ? _BaseType(0.0) : (v3->x - v1->x) / (v3->y - v1->y); + _BaseType dxdy_v2v3 = (v3->y == v2->y) ? _BaseType(0.0) : (v3->x - v2->x) / (v3->y - v2->y); + + // compute parameter starting points and deltas + _BaseType param_start[_MaxParams]; + _BaseType param_dpdx[_MaxParams]; + _BaseType param_dpdy[_MaxParams]; + if (paramcount > 0) + { + _BaseType a00 = v2->y - v3->y; + _BaseType a01 = v3->x - v2->x; + _BaseType a02 = v2->x*v3->y - v3->x*v2->y; + _BaseType a10 = v3->y - v1->y; + _BaseType a11 = v1->x - v3->x; + _BaseType a12 = v3->x*v1->y - v1->x*v3->y; + _BaseType a20 = v1->y - v2->y; + _BaseType a21 = v2->x - v1->x; + _BaseType a22 = v1->x*v2->y - v2->x*v1->y; + _BaseType det = a02 + a12 + a22; + + if (poly_abs(det) < _BaseType(0.00001)) + { + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + param_dpdx[paramnum] = _BaseType(0.0); + param_dpdy[paramnum] = _BaseType(0.0); + param_start[paramnum] = v1->p[paramnum]; + } + } + else + { + _BaseType idet = poly_recip(det); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + param_dpdx[paramnum] = idet * (v1->p[paramnum]*a00 + v2->p[paramnum]*a10 + v3->p[paramnum]*a20); + param_dpdy[paramnum] = idet * (v1->p[paramnum]*a01 + v2->p[paramnum]*a11 + v3->p[paramnum]*a21); + param_start[paramnum] = idet * (v1->p[paramnum]*a02 + v2->p[paramnum]*a12 + v3->p[paramnum]*a22); + } + } + } + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = v1yclip; curscan < v3yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(v3yclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + // compute the ending X based on which part of the triangle we're in + _BaseType fully = _BaseType(curscan + extnum) + _BaseType(0.5); + _BaseType startx = v1->x + (fully - v1->y) * dxdy_v1v3; + _BaseType stopx; + if (fully < v2->y) + stopx = v1->x + (fully - v1->y) * dxdy_v1v2; + else + stopx = v2->x + (fully - v2->y) * dxdy_v2v3; + + // clamp to full pixels + INT32 istartx = round_coordinate(startx); + INT32 istopx = round_coordinate(stopx); + + // force start < stop + if (istartx > istopx) + { + INT32 temp = istartx; + istartx = istopx; + istopx = temp; + } + + // include the right edge if requested + if (m_flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + // apply left/right clipping + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + // set the extent and update the total pixel count + if (istartx >= istopx) + istartx = istopx = 0; + extent_t &extent = unit.extent[extnum]; + extent.startx = istartx; + extent.stopx = istopx; + pixels += istopx - istartx; + + // fill in the parameters for the extent + _BaseType fullstartx = _BaseType(istartx) + _BaseType(0.5); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + extent.param[paramnum].start = param_start[paramnum] + fullstartx * param_dpdx[paramnum] + fully * param_dpdy[paramnum]; + extent.param[paramnum].dpdx = param_dpdx[paramnum]; + } + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the triangle + m_triangles++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// render_triangle_fan - render a set of +// triangles in a fan +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle_fan(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v) +{ + // iterate over vertices + UINT32 pixels = 0; + for (int vertnum = 2; vertnum < numverts; vertnum++) + pixels += render_triangle(cliprect, callback, paramcount, v[0], v[vertnum - 1], v[vertnum]); + return pixels; +} + + +//------------------------------------------------- +// render_triangle_strip - render a set of +// triangles in a strip +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle_strip(const rectangle &cliprect, render_delegate callback, int paramcount, int numverts, const vertex_t *v) +{ + // iterate over vertices + UINT32 pixels = 0; + for (int vertnum = 2; vertnum < numverts; vertnum++) + pixels += render_triangle(cliprect, callback, paramcount, v[vertnum - 2], v[vertnum - 1], v[vertnum]); + return pixels; +} + + +//------------------------------------------------- +// render_triangle_custom - perform a custom +// render of an object, given specific extents +//------------------------------------------------- + +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_triangle_custom(const rectangle &cliprect, render_delegate callback, int startscanline, int numscanlines, const extent_t *extents) +{ + // clip coordinates + INT32 v1yclip = MAX(startscanline, cliprect.min_y); + INT32 v3yclip = MIN(startscanline + numscanlines, cliprect.max_y + 1); + if (v3yclip - v1yclip <= 0) + return 0; + + // allocate and populate a new polygon + polygon_info &polygon = polygon_alloc(0, 0, v1yclip, v3yclip, callback); + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = v1yclip; curscan < v3yclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(v3yclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + const extent_t &srcextent = extents[(curscan + extnum) - startscanline]; + INT32 istartx = srcextent.startx, istopx = srcextent.stopx; + + // force start < stop + if (istartx > istopx) + { + INT32 temp = istartx; + istartx = istopx; + istopx = temp; + } + + // apply left/right clipping + if (istartx < cliprect.min_x) + istartx = cliprect.min_x; + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + // set the extent and update the total pixel count + extent_t &extent = unit.extent[extnum]; + extent.startx = istartx; + extent.stopx = istopx; + if (istartx < istopx) + pixels += istopx - istartx; + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the object + m_triangles++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// render_polygon - render a single polygon up +// to 32 vertices +//------------------------------------------------- + +template +template +UINT32 poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::render_polygon(const rectangle &cliprect, render_delegate callback, int paramcount, const vertex_t *v) +{ + // determine min/max Y vertices + _BaseType minx = v[0].x; + _BaseType maxx = v[0].x; + int minv = 0; + int maxv = 0; + for (int vertnum = 1; vertnum < _NumVerts; vertnum++) + { + if (v[vertnum].y < v[minv].y) + minv = vertnum; + else if (v[vertnum].y > v[maxv].y) + maxv = vertnum; + if (v[vertnum].x < minx) + minx = v[vertnum].x; + else if (v[vertnum].x > maxx) + maxx = v[vertnum].x; + } + + // determine start/end scanlines + INT32 miny = round_coordinate(v[minv].y); + INT32 maxy = round_coordinate(v[maxv].y); + + // clip coordinates + INT32 minyclip = miny; + INT32 maxyclip = maxy + ((m_flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0); + minyclip = MAX(minyclip, cliprect.min_y); + maxyclip = MIN(maxyclip, cliprect.max_y + 1); + if (maxyclip - minyclip <= 0) + return 0; + + // allocate a new polygon + polygon_info &polygon = polygon_alloc(round_coordinate(minx), round_coordinate(maxx), minyclip, maxyclip, callback); + + // walk forward to build up the forward edge list + struct poly_edge + { + poly_edge * next; // next edge in sequence + int index; // index of this edge + const vertex_t * v1; // pointer to first vertex + const vertex_t * v2; // pointer to second vertex + _BaseType dxdy; // dx/dy along the edge + _BaseType dpdy[_MaxParams]; // per-parameter dp/dy values + }; + poly_edge fedgelist[_NumVerts - 1]; + poly_edge *edgeptr = &fedgelist[0]; + for (int curv = minv; curv != maxv; curv = (curv == _NumVerts - 1) ? 0 : (curv + 1)) + { + // set the two vertices + edgeptr->v1 = &v[curv]; + edgeptr->v2 = &v[(curv == _NumVerts - 1) ? 0 : (curv + 1)]; + + // if horizontal, skip altogether + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + // need dx/dy always, and parameter deltas as necessary + _BaseType ooy = poly_recip(edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (int paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + // walk backward to build up the backward edge list + poly_edge bedgelist[_NumVerts - 1]; + edgeptr = &bedgelist[0]; + for (int curv = minv; curv != maxv; curv = (curv == 0) ? (_NumVerts - 1) : (curv - 1)) + { + // set the two vertices + edgeptr->v1 = &v[curv]; + edgeptr->v2 = &v[(curv == 0) ? (_NumVerts - 1) : (curv - 1)]; + + // if horizontal, skip altogether + if (edgeptr->v1->y == edgeptr->v2->y) + continue; + + // need dx/dy always, and parameter deltas as necessary + _BaseType ooy = poly_recip(edgeptr->v2->y - edgeptr->v1->y); + edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; + for (int paramnum = 0; paramnum < paramcount; paramnum++) + edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy; + edgeptr++; + } + + // determine which list is left/right: + // if the first vertex is shared, compare the slopes + // if the first vertex is not shared, compare the X coordinates + const poly_edge *ledge, *redge; + if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) || + (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x)) + { + ledge = fedgelist; + redge = bedgelist; + } + else + { + ledge = bedgelist; + redge = fedgelist; + } + + // compute the X extents for each scanline + INT32 pixels = 0; + UINT32 startunit = m_unit.count(); + INT32 scaninc = 1; + for (INT32 curscan = minyclip; curscan < maxyclip; curscan += scaninc) + { + UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; + UINT32 unit_index = m_unit.count(); + work_unit &unit = m_unit.next(); + + // determine how much to advance to hit the next bucket + scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET; + + // fill in the work unit basics + unit.polygon = &polygon; + unit.count_next = MIN(maxyclip - curscan, scaninc); + unit.scanline = curscan; + unit.previtem = m_unit_bucket[bucketnum]; + m_unit_bucket[bucketnum] = unit_index; + + // iterate over extents + for (int extnum = 0; extnum < unit.count_next; extnum++) + { + // compute the ending X based on which part of the triangle we're in + _BaseType fully = _BaseType(curscan + extnum) + _BaseType(0.5); + while (fully > ledge->v2->y && fully < v[maxv].y) + ledge++; + while (fully > redge->v2->y && fully < v[maxv].y) + redge++; + _BaseType startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy; + _BaseType stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy; + + // clamp to full pixels + INT32 istartx = round_coordinate(startx); + INT32 istopx = round_coordinate(stopx); + + // compute parameter starting points and deltas + extent_t &extent = unit.extent[extnum]; + if (paramcount > 0) + { + _BaseType ldy = fully - ledge->v1->y; + _BaseType rdy = fully - redge->v1->y; + _BaseType oox = poly_recip(stopx - startx); + + // iterate over parameters + for (int paramnum = 0; paramnum < paramcount; paramnum++) + { + _BaseType lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; + _BaseType rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; + _BaseType dpdx = (rparam - lparam) * oox; + + extent.param[paramnum].start = lparam;// - (_BaseType(istartx) + 0.5f) * dpdx; + extent.param[paramnum].dpdx = dpdx; + } + } + + // include the right edge if requested + if (m_flags & POLYFLAG_INCLUDE_RIGHT_EDGE) + istopx++; + + // apply left/right clipping + if (istartx < cliprect.min_x) + { + for (int paramnum = 0; paramnum < paramcount; paramnum++) + extent.param[paramnum].start += (cliprect.min_x - istartx) * extent.param[paramnum].dpdx; + istartx = cliprect.min_x; + } + if (istopx > cliprect.max_x) + istopx = cliprect.max_x + 1; + + // set the extent and update the total pixel count + if (istartx >= istopx) + istartx = istopx = 0; + extent.startx = istartx; + extent.stopx = istopx; + pixels += istopx - istartx; + } + } + + // enqueue the work items + if (m_queue != NULL) + osd_work_item_queue_multiple(m_queue, work_item_callback, m_unit.count() - startunit, &m_unit[startunit], m_unit.itemsize(), WORK_ITEM_FLAG_AUTO_RELEASE); + + // return the total number of pixels in the triangle + m_quads++; + m_pixels += pixels; + return pixels; +} + + +//------------------------------------------------- +// zclip_if_less - clip a polygon using p[0] as +// a z coordinate +//------------------------------------------------- + +template +int poly_manager<_BaseType, _ObjectData, _MaxParams, _MaxPolys>::zclip_if_less(int numverts, const vertex_t *v, vertex_t *outv, int paramcount, _BaseType clipval) +{ + bool prevclipped = (v[numverts - 1]->p[0] < clipval); + vertex_t *nextout = outv; + + // iterate over vertices + for (int vertnum = 0; vertnum < numverts; vertnum++) + { + bool thisclipped = (v[vertnum]->p[0] < clipval); + + // if we switched from clipped to non-clipped, interpolate a vertex + if (thisclipped != prevclipped) + { + const vertex_t &v1 = v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)]; + const vertex_t &v2 = v[vertnum]; + _BaseType frac = (clipval - v1.p[0]) / (v2.p[0] - v1.p[0]); + nextout.x = v1.x + frac * (v2.x - v1.x); + nextout.y = v1.y + frac * (v2.y - v1.y); + for (int paramnum = 0; paramnum < paramcount; paramnum++) + nextout.p[paramnum] = v1.p[paramnum] + frac * (v2.p[paramnum] - v1.p[paramnum]); + nextout++; + } + + // if this vertex is not clipped, copy it in + if (!thisclipped) + *nextout++ = v[vertnum]; + + // remember the last state + prevclipped = thisclipped; + } + return nextout - outv; +} + +#endif // __POLYNEW_H__ diff --git a/src/mame/drivers/gaelco3d.c b/src/mame/drivers/gaelco3d.c index 7bcabea184c..14d617767c7 100644 --- a/src/mame/drivers/gaelco3d.c +++ b/src/mame/drivers/gaelco3d.c @@ -1217,34 +1217,6 @@ ROM_END static DRIVER_INIT( gaelco3d ) { - gaelco3d_state *state = machine.driver_data(); - UINT8 *src, *dst; - int x, y; - - /* allocate memory */ - state->m_texture_size = machine.region("gfx1")->bytes(); - state->m_texmask_size = machine.region("gfx2")->bytes() * 8; - state->m_texture = auto_alloc_array(machine, UINT8, state->m_texture_size); - state->m_texmask = auto_alloc_array(machine, UINT8, state->m_texmask_size); - - /* first expand the pixel data */ - src = machine.region("gfx1")->base(); - dst = state->m_texture; - for (y = 0; y < state->m_texture_size/4096; y += 2) - for (x = 0; x < 4096; x += 2) - { - dst[(y + 0) * 4096 + (x + 1)] = src[0*state->m_texture_size/4 + (y/2) * 2048 + (x/2)]; - dst[(y + 1) * 4096 + (x + 1)] = src[1*state->m_texture_size/4 + (y/2) * 2048 + (x/2)]; - dst[(y + 0) * 4096 + (x + 0)] = src[2*state->m_texture_size/4 + (y/2) * 2048 + (x/2)]; - dst[(y + 1) * 4096 + (x + 0)] = src[3*state->m_texture_size/4 + (y/2) * 2048 + (x/2)]; - } - - /* then expand the mask data */ - src = machine.region("gfx2")->base(); - dst = state->m_texmask; - for (y = 0; y < state->m_texmask_size/4096; y++) - for (x = 0; x < 4096; x++) - dst[y * 4096 + x] = (src[(x / 1024) * (state->m_texmask_size/8/4) + (y * 1024 + x % 1024) / 8] >> (x % 8)) & 1; } diff --git a/src/mame/includes/gaelco3d.h b/src/mame/includes/gaelco3d.h index a319a20ca0e..cf513b12feb 100644 --- a/src/mame/includes/gaelco3d.h +++ b/src/mame/includes/gaelco3d.h @@ -7,10 +7,46 @@ **************************************************************************/ #include "sound/dmadac.h" -#include "video/poly.h" +#include "video/polynew.h" #define SOUND_CHANNELS 4 +struct gaelco3d_object_data +{ + UINT32 tex, color; + float ooz_dx, ooz_dy, ooz_base; + float uoz_dx, uoz_dy, uoz_base; + float voz_dx, voz_dy, voz_base; + float z0; +}; + +class gaelco3d_state; + +class gaelco3d_renderer : public poly_manager +{ +public: + gaelco3d_renderer(gaelco3d_state &state); + + bitmap_t *screenbits() const { return m_screenbits; } + UINT32 polygons() { UINT32 result = m_polygons; m_polygons = 0; return result; } + + void render_poly(screen_device &screen, UINT32 *polydata); + +private: + gaelco3d_state &m_state; + bitmap_t *m_screenbits; + bitmap_t *m_zbuffer; + UINT32 m_polygons; + offs_t m_texture_size; + offs_t m_texmask_size; + UINT8 *m_texture; + UINT8 *m_texmask; + + void render_noz_noperspective(INT32 scanline, const extent_t &extent, const gaelco3d_object_data &extra, int threadid); + void render_normal(INT32 scanline, const extent_t &extent, const gaelco3d_object_data &extra, int threadid); + void render_alphablend(INT32 scanline, const extent_t &extent, const gaelco3d_object_data &extra, int threadid); +}; + class gaelco3d_state : public driver_device { public: @@ -33,19 +69,12 @@ public: offs_t m_adsp_incs; offs_t m_adsp_size; dmadac_sound_device *m_dmadac[SOUND_CHANNELS]; - UINT8 *m_texture; - UINT8 *m_texmask; - offs_t m_texture_size; - offs_t m_texmask_size; - bitmap_t *m_screenbits; - bitmap_t *m_zbuffer; rgb_t *m_palette; UINT32 *m_polydata_buffer; UINT32 m_polydata_count; - int m_polygons; int m_lastscan; int m_video_changed; - poly_manager *m_poly; + gaelco3d_renderer *m_poly; }; diff --git a/src/mame/includes/midvunit.h b/src/mame/includes/midvunit.h index 3b489714ac5..1016eda8472 100644 --- a/src/mame/includes/midvunit.h +++ b/src/mame/includes/midvunit.h @@ -4,10 +4,36 @@ **************************************************************************/ -#include "video/poly.h" +#include "video/polynew.h" #define MIDVUNIT_VIDEO_CLOCK 33000000 +struct midvunit_object_data +{ + UINT16 * destbase; + UINT8 * texbase; + UINT16 pixdata; + UINT8 dither; +}; + +class midvunit_state; + +class midvunit_renderer : public poly_manager +{ +public: + midvunit_renderer(midvunit_state &state); + void process_dma_queue(); + void make_vertices_inclusive(vertex_t *vert); + +private: + midvunit_state &m_state; + + void render_flat(INT32 scanline, const extent_t &extent, const midvunit_object_data &extradata, int threadid); + void render_tex(INT32 scanline, const extent_t &extent, const midvunit_object_data &extradata, int threadid); + void render_textrans(INT32 scanline, const extent_t &extent, const midvunit_object_data &extradata, int threadid); + void render_textransmask(INT32 scanline, const extent_t &extent, const midvunit_object_data &extradata, int threadid); +}; + class midvunit_state : public driver_device { public: @@ -39,7 +65,7 @@ public: UINT16 m_page_control; UINT8 m_video_changed; emu_timer *m_scanline_timer; - poly_manager *m_poly; + midvunit_renderer *m_poly; }; diff --git a/src/mame/video/gaelco3d.c b/src/mame/video/gaelco3d.c index aa596bde006..338861e207a 100644 --- a/src/mame/video/gaelco3d.c +++ b/src/mame/video/gaelco3d.c @@ -24,23 +24,39 @@ #define IS_POLYEND(x) (((x) ^ ((x) >> 1)) & 0x4000) -struct poly_extra_data +gaelco3d_renderer::gaelco3d_renderer(gaelco3d_state &state) + : poly_manager(state.machine()), + m_state(state), + m_screenbits(machine().primary_screen->alloc_compatible_bitmap()), + m_zbuffer(auto_bitmap_alloc(state.machine(), state.machine().primary_screen->width(), state.machine().primary_screen->height(), BITMAP_FORMAT_INDEXED16)), + m_polygons(0), + m_texture_size(state.machine().region("gfx1")->bytes()), + m_texmask_size(state.machine().region("gfx2")->bytes() * 8), + m_texture(auto_alloc_array(state.machine(), UINT8, m_texture_size)), + m_texmask(auto_alloc_array(state.machine(), UINT8, m_texmask_size)) { - running_machine &machine() const { assert(m_machine != NULL); return *m_machine; } + state_save_register_global_bitmap(state.machine(), m_screenbits); + state_save_register_global_bitmap(state.machine(), m_zbuffer); - running_machine *m_machine; - UINT32 tex, color; - float ooz_dx, ooz_dy, ooz_base; - float uoz_dx, uoz_dy, uoz_base; - float voz_dx, voz_dy, voz_base; - float z0; -}; - - -static void render_noz_noperspective(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); -static void render_normal(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); -static void render_alphablend(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid); + /* first expand the pixel data */ + UINT8 *src = state.machine().region("gfx1")->base(); + UINT8 *dst = m_texture; + for (int y = 0; y < m_texture_size/4096; y += 2) + for (int x = 0; x < 4096; x += 2) + { + dst[(y + 0) * 4096 + (x + 1)] = src[0*m_texture_size/4 + (y/2) * 2048 + (x/2)]; + dst[(y + 1) * 4096 + (x + 1)] = src[1*m_texture_size/4 + (y/2) * 2048 + (x/2)]; + dst[(y + 0) * 4096 + (x + 0)] = src[2*m_texture_size/4 + (y/2) * 2048 + (x/2)]; + dst[(y + 1) * 4096 + (x + 0)] = src[3*m_texture_size/4 + (y/2) * 2048 + (x/2)]; + } + /* then expand the mask data */ + src = state.machine().region("gfx2")->base(); + dst = m_texmask; + for (int y = 0; y < m_texmask_size/4096; y++) + for (int x = 0; x < 4096; x++) + dst[y * 4096 + x] = (src[(x / 1024) * (m_texmask_size/8/4) + (y * 1024 + x % 1024) / 8] >> (x % 8)) & 1; +} /************************************* @@ -49,26 +65,11 @@ static void render_alphablend(void *dest, INT32 scanline, const poly_extent *ext * *************************************/ -static void gaelco3d_exit(running_machine &machine) -{ - gaelco3d_state *state = machine.driver_data(); - poly_free(state->m_poly); -} - - VIDEO_START( gaelco3d ) { gaelco3d_state *state = machine.driver_data(); - int width, height; - state->m_poly = poly_alloc(machine, 2000, sizeof(poly_extra_data), 0); - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(gaelco3d_exit), &machine)); - - state->m_screenbits = machine.primary_screen->alloc_compatible_bitmap(); - - width = machine.primary_screen->width(); - height = machine.primary_screen->height(); - state->m_zbuffer = auto_bitmap_alloc(machine, width, height, BITMAP_FORMAT_INDEXED16); + state->m_poly = auto_alloc(machine, gaelco3d_renderer(*state)); state->m_palette = auto_alloc_array(machine, rgb_t, 32768); state->m_polydata_buffer = auto_alloc_array(machine, UINT32, MAX_POLYDATA); @@ -79,11 +80,7 @@ VIDEO_START( gaelco3d ) state_save_register_global_pointer(machine, state->m_polydata_buffer, MAX_POLYDATA); state_save_register_global(machine, state->m_polydata_count); - state_save_register_global(machine, state->m_polygons); state_save_register_global(machine, state->m_lastscan); - - state_save_register_global_bitmap(machine, state->m_screenbits); - state_save_register_global_bitmap(machine, state->m_zbuffer); } @@ -115,9 +112,8 @@ VIDEO_START( gaelco3d ) (repeat these two for each additional point in the fan) */ -static void render_poly(screen_device &screen, UINT32 *polydata) +void gaelco3d_renderer::render_poly(screen_device &screen, UINT32 *polydata) { - gaelco3d_state *state = screen.machine().driver_data(); float midx = screen.width() / 2; float midy = screen.height() / 2; float z0 = tms3203x_device::fp_to_float(polydata[0]); @@ -130,9 +126,9 @@ static void render_poly(screen_device &screen, UINT32 *polydata) float voz_base = tms3203x_device::fp_to_float(polydata[7]) * 256.0f - midx * voz_dx - midy * voz_dy; float ooz_base = tms3203x_device::fp_to_float(polydata[8]) - midx * ooz_dx - midy * ooz_dy; float uoz_base = tms3203x_device::fp_to_float(polydata[9]) * 256.0f - midx * uoz_dx - midy * uoz_dy; - poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(state->m_poly); + gaelco3d_object_data &object = object_data_alloc(); int color = (polydata[10] & 0x7f) << 8; - poly_vertex vert[MAX_VERTICES]; + vertex_t vert[MAX_VERTICES]; UINT32 data; int vertnum; @@ -160,20 +156,19 @@ static void render_poly(screen_device &screen, UINT32 *polydata) logerror("\n"); } - /* fill in extra data */ - extra->m_machine = &screen.machine(); - extra->tex = polydata[11]; - extra->color = color; - extra->ooz_dx = ooz_dx; - extra->ooz_dy = ooz_dy; - extra->ooz_base = ooz_base; - extra->uoz_dx = uoz_dx; - extra->uoz_dy = uoz_dy; - extra->uoz_base = uoz_base; - extra->voz_dx = voz_dx; - extra->voz_dy = voz_dy; - extra->voz_base = voz_base; - extra->z0 = z0; + /* fill in object data */ + object.tex = polydata[11]; + object.color = color; + object.ooz_dx = ooz_dx; + object.ooz_dy = ooz_dy; + object.ooz_base = ooz_base; + object.uoz_dx = uoz_dx; + object.uoz_dy = uoz_dy; + object.uoz_base = uoz_base; + object.voz_dx = voz_dx; + object.voz_dy = voz_dy; + object.voz_base = voz_base; + object.z0 = z0; /* extract vertices */ data = 0; @@ -192,52 +187,49 @@ static void render_poly(screen_device &screen, UINT32 *polydata) /* special case: no Z buffering and no perspective correction */ if (color != 0x7f00 && z0 < 0 && ooz_dx == 0 && ooz_dy == 0) - poly_render_triangle_fan(state->m_poly, state->m_screenbits, &visarea, render_noz_noperspective, 0, vertnum, &vert[0]); + render_triangle_fan(visarea, render_delegate(FUNC(gaelco3d_renderer::render_noz_noperspective), this), 0, vertnum, &vert[0]); /* general case: non-alpha blended */ else if (color != 0x7f00) - poly_render_triangle_fan(state->m_poly, state->m_screenbits, &visarea, render_normal, 0, vertnum, &vert[0]); + render_triangle_fan(visarea, render_delegate(FUNC(gaelco3d_renderer::render_normal), this), 0, vertnum, &vert[0]); /* color 0x7f seems to be hard-coded as a 50% alpha blend */ else - poly_render_triangle_fan(state->m_poly, state->m_screenbits, &visarea, render_alphablend, 0, vertnum, &vert[0]); + render_triangle_fan(visarea, render_delegate(FUNC(gaelco3d_renderer::render_alphablend), this), 0, vertnum, &vert[0]); - state->m_polygons += vertnum - 2; + m_polygons += vertnum - 2; } } -static void render_noz_noperspective(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) +void gaelco3d_renderer::render_noz_noperspective(INT32 scanline, const extent_t &extent, const gaelco3d_object_data &object, int threadid) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - gaelco3d_state *state = extra->machine().driver_data(); - bitmap_t *bitmap = (bitmap_t *)destbase; - float zbase = recip_approx(extra->ooz_base); - float uoz_step = extra->uoz_dx * zbase; - float voz_step = extra->voz_dx * zbase; - int zbufval = (int)(-extra->z0 * zbase); - offs_t endmask = state->m_texture_size - 1; - const rgb_t *palsource = state->m_palette + extra->color; - UINT32 tex = extra->tex; - UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0); - UINT16 *zbuf = BITMAP_ADDR16(state->m_zbuffer, scanline, 0); - int startx = extent->startx; - float uoz = (extra->uoz_base + scanline * extra->uoz_dy + startx * extra->uoz_dx) * zbase; - float voz = (extra->voz_base + scanline * extra->voz_dy + startx * extra->voz_dx) * zbase; + float zbase = recip_approx(object.ooz_base); + float uoz_step = object.uoz_dx * zbase; + float voz_step = object.voz_dx * zbase; + int zbufval = (int)(-object.z0 * zbase); + offs_t endmask = m_texture_size - 1; + const rgb_t *palsource = m_state.m_palette + object.color; + UINT32 tex = object.tex; + UINT16 *dest = BITMAP_ADDR16(m_screenbits, scanline, 0); + UINT16 *zbuf = BITMAP_ADDR16(m_zbuffer, scanline, 0); + int startx = extent.startx; + float uoz = (object.uoz_base + scanline * object.uoz_dy + startx * object.uoz_dx) * zbase; + float voz = (object.voz_base + scanline * object.voz_dy + startx * object.voz_dx) * zbase; int x; - for (x = startx; x < extent->stopx; x++) + for (x = startx; x < extent.stopx; x++) { int u = (int)uoz; int v = (int)voz; int pixeloffs = (tex + (v >> 8) * 4096 + (u >> 8)) & endmask; - if (pixeloffs >= state->m_texmask_size || !state->m_texmask[pixeloffs]) + if (pixeloffs >= m_texmask_size || !m_texmask[pixeloffs]) { - rgb_t rgb00 = palsource[state->m_texture[pixeloffs]]; - rgb_t rgb01 = palsource[state->m_texture[(pixeloffs + 1) & endmask]]; - rgb_t rgb10 = palsource[state->m_texture[(pixeloffs + 4096) & endmask]]; - rgb_t rgb11 = palsource[state->m_texture[(pixeloffs + 4097) & endmask]]; + rgb_t rgb00 = palsource[m_texture[pixeloffs]]; + rgb_t rgb01 = palsource[m_texture[(pixeloffs + 1) & endmask]]; + rgb_t rgb10 = palsource[m_texture[(pixeloffs + 4096) & endmask]]; + rgb_t rgb11 = palsource[m_texture[(pixeloffs + 4097) & endmask]]; rgb_t filtered = rgb_bilinear_filter(rgb00, rgb01, rgb10, rgb11, u, v); dest[x] = (filtered & 0x1f) | ((filtered & 0x1ff800) >> 6); zbuf[x] = zbufval; @@ -250,27 +242,24 @@ static void render_noz_noperspective(void *destbase, INT32 scanline, const poly_ } -static void render_normal(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) +void gaelco3d_renderer::render_normal(INT32 scanline, const extent_t &extent, const gaelco3d_object_data &object, int threadid) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - gaelco3d_state *state = extra->machine().driver_data(); - bitmap_t *bitmap = (bitmap_t *)destbase; - float ooz_dx = extra->ooz_dx; - float uoz_dx = extra->uoz_dx; - float voz_dx = extra->voz_dx; - offs_t endmask = state->m_texture_size - 1; - const rgb_t *palsource = state->m_palette + extra->color; - UINT32 tex = extra->tex; - float z0 = extra->z0; - UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0); - UINT16 *zbuf = BITMAP_ADDR16(state->m_zbuffer, scanline, 0); - int startx = extent->startx; - float ooz = extra->ooz_base + scanline * extra->ooz_dy + startx * ooz_dx; - float uoz = extra->uoz_base + scanline * extra->uoz_dy + startx * uoz_dx; - float voz = extra->voz_base + scanline * extra->voz_dy + startx * voz_dx; + float ooz_dx = object.ooz_dx; + float uoz_dx = object.uoz_dx; + float voz_dx = object.voz_dx; + offs_t endmask = m_texture_size - 1; + const rgb_t *palsource = m_state.m_palette + object.color; + UINT32 tex = object.tex; + float z0 = object.z0; + UINT16 *dest = BITMAP_ADDR16(m_screenbits, scanline, 0); + UINT16 *zbuf = BITMAP_ADDR16(m_zbuffer, scanline, 0); + int startx = extent.startx; + float ooz = object.ooz_base + scanline * object.ooz_dy + startx * ooz_dx; + float uoz = object.uoz_base + scanline * object.uoz_dy + startx * uoz_dx; + float voz = object.voz_base + scanline * object.voz_dy + startx * voz_dx; int x; - for (x = startx; x < extent->stopx; x++) + for (x = startx; x < extent.stopx; x++) { if (ooz > 0) { @@ -282,12 +271,12 @@ static void render_normal(void *destbase, INT32 scanline, const poly_extent *ext int u = (int)(uoz * z); int v = (int)(voz * z); int pixeloffs = (tex + (v >> 8) * 4096 + (u >> 8)) & endmask; - if (pixeloffs >= state->m_texmask_size || !state->m_texmask[pixeloffs]) + if (pixeloffs >= m_texmask_size || !m_texmask[pixeloffs]) { - rgb_t rgb00 = palsource[state->m_texture[pixeloffs]]; - rgb_t rgb01 = palsource[state->m_texture[(pixeloffs + 1) & endmask]]; - rgb_t rgb10 = palsource[state->m_texture[(pixeloffs + 4096) & endmask]]; - rgb_t rgb11 = palsource[state->m_texture[(pixeloffs + 4097) & endmask]]; + rgb_t rgb00 = palsource[m_texture[pixeloffs]]; + rgb_t rgb01 = palsource[m_texture[(pixeloffs + 1) & endmask]]; + rgb_t rgb10 = palsource[m_texture[(pixeloffs + 4096) & endmask]]; + rgb_t rgb11 = palsource[m_texture[(pixeloffs + 4097) & endmask]]; rgb_t filtered = rgb_bilinear_filter(rgb00, rgb01, rgb10, rgb11, u, v); dest[x] = (filtered & 0x1f) | ((filtered & 0x1ff800) >> 6); zbuf[x] = (zbufval < 0) ? -zbufval : zbufval; @@ -303,27 +292,24 @@ static void render_normal(void *destbase, INT32 scanline, const poly_extent *ext } -static void render_alphablend(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) +void gaelco3d_renderer::render_alphablend(INT32 scanline, const extent_t &extent, const gaelco3d_object_data &object, int threadid) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - gaelco3d_state *state = extra->machine().driver_data(); - bitmap_t *bitmap = (bitmap_t *)destbase; - float ooz_dx = extra->ooz_dx; - float uoz_dx = extra->uoz_dx; - float voz_dx = extra->voz_dx; - offs_t endmask = state->m_texture_size - 1; - const rgb_t *palsource = state->m_palette + extra->color; - UINT32 tex = extra->tex; - float z0 = extra->z0; - UINT16 *dest = BITMAP_ADDR16(bitmap, scanline, 0); - UINT16 *zbuf = BITMAP_ADDR16(state->m_zbuffer, scanline, 0); - int startx = extent->startx; - float ooz = extra->ooz_base + extra->ooz_dy * scanline + startx * ooz_dx; - float uoz = extra->uoz_base + extra->uoz_dy * scanline + startx * uoz_dx; - float voz = extra->voz_base + extra->voz_dy * scanline + startx * voz_dx; + float ooz_dx = object.ooz_dx; + float uoz_dx = object.uoz_dx; + float voz_dx = object.voz_dx; + offs_t endmask = m_texture_size - 1; + const rgb_t *palsource = m_state.m_palette + object.color; + UINT32 tex = object.tex; + float z0 = object.z0; + UINT16 *dest = BITMAP_ADDR16(m_screenbits, scanline, 0); + UINT16 *zbuf = BITMAP_ADDR16(m_zbuffer, scanline, 0); + int startx = extent.startx; + float ooz = object.ooz_base + object.ooz_dy * scanline + startx * ooz_dx; + float uoz = object.uoz_base + object.uoz_dy * scanline + startx * uoz_dx; + float voz = object.voz_base + object.voz_dy * scanline + startx * voz_dx; int x; - for (x = startx; x < extent->stopx; x++) + for (x = startx; x < extent.stopx; x++) { if (ooz > 0) { @@ -335,12 +321,12 @@ static void render_alphablend(void *destbase, INT32 scanline, const poly_extent int u = (int)(uoz * z); int v = (int)(voz * z); int pixeloffs = (tex + (v >> 8) * 4096 + (u >> 8)) & endmask; - if (pixeloffs >= state->m_texmask_size || !state->m_texmask[pixeloffs]) + if (pixeloffs >= m_texmask_size || !m_texmask[pixeloffs]) { - rgb_t rgb00 = palsource[state->m_texture[pixeloffs]]; - rgb_t rgb01 = palsource[state->m_texture[(pixeloffs + 1) & endmask]]; - rgb_t rgb10 = palsource[state->m_texture[(pixeloffs + 4096) & endmask]]; - rgb_t rgb11 = palsource[state->m_texture[(pixeloffs + 4097) & endmask]]; + rgb_t rgb00 = palsource[m_texture[pixeloffs]]; + rgb_t rgb01 = palsource[m_texture[(pixeloffs + 1) & endmask]]; + rgb_t rgb10 = palsource[m_texture[(pixeloffs + 4096) & endmask]]; + rgb_t rgb11 = palsource[m_texture[(pixeloffs + 4097) & endmask]]; rgb_t filtered = rgb_bilinear_filter(rgb00, rgb01, rgb10, rgb11, u, v) >> 1; dest[x] = ((filtered & 0x0f) | ((filtered & 0x0f7800) >> 6)) + ((dest[x] >> 1) & 0x3def); zbuf[x] = (zbufval < 0) ? -zbufval : zbufval; @@ -366,17 +352,16 @@ void gaelco3d_render(screen_device &screen) { gaelco3d_state *state = screen.machine().driver_data(); /* wait for any queued stuff to complete */ - poly_wait(state->m_poly, "Time to render"); + state->m_poly->wait("Time to render"); #if DISPLAY_STATS { int scan = screen.vpos(); - popmessage("Polys = %4d Timeleft = %3d", state->m_polygons, (state->m_lastscan < scan) ? (scan - state->m_lastscan) : (scan + (state->m_lastscan - screen.visible_area().max_y))); + popmessage("Polys = %4d Timeleft = %3d", state->m_poly->polygons(), (state->m_lastscan < scan) ? (scan - state->m_lastscan) : (scan + (state->m_lastscan - screen.visible_area().max_y))); } #endif state->m_polydata_count = 0; - state->m_polygons = 0; state->m_lastscan = -1; } @@ -401,7 +386,7 @@ WRITE32_HANDLER( gaelco3d_render_w ) { if (state->m_polydata_count >= 18 && (state->m_polydata_count % 2) == 1 && IS_POLYEND(state->m_polydata_buffer[state->m_polydata_count - 2])) { - render_poly(*space->machine().primary_screen, &state->m_polydata_buffer[0]); + state->m_poly->render_poly(*space->machine().primary_screen, &state->m_polydata_buffer[0]); state->m_polydata_count = 0; } state->m_video_changed = TRUE; @@ -423,7 +408,7 @@ WRITE32_HANDLER( gaelco3d_render_w ) WRITE16_HANDLER( gaelco3d_paletteram_w ) { gaelco3d_state *state = space->machine().driver_data(); - poly_wait(state->m_poly, "Palette change"); + state->m_poly->wait("Palette change"); COMBINE_DATA(&space->machine().generic.paletteram.u16[offset]); state->m_palette[offset] = ((space->machine().generic.paletteram.u16[offset] & 0x7fe0) << 6) | (space->machine().generic.paletteram.u16[offset] & 0x1f); } @@ -432,7 +417,7 @@ WRITE16_HANDLER( gaelco3d_paletteram_w ) WRITE32_HANDLER( gaelco3d_paletteram_020_w ) { gaelco3d_state *state = space->machine().driver_data(); - poly_wait(state->m_poly, "Palette change"); + state->m_poly->wait("Palette change"); COMBINE_DATA(&space->machine().generic.paletteram.u32[offset]); state->m_palette[offset*2+0] = ((space->machine().generic.paletteram.u32[offset] & 0x7fe00000) >> 10) | ((space->machine().generic.paletteram.u32[offset] & 0x1f0000) >> 16); state->m_palette[offset*2+1] = ((space->machine().generic.paletteram.u32[offset] & 0x7fe0) << 6) | (space->machine().generic.paletteram.u32[offset] & 0x1f); @@ -449,8 +434,9 @@ WRITE32_HANDLER( gaelco3d_paletteram_020_w ) SCREEN_UPDATE( gaelco3d ) { gaelco3d_state *state = screen->machine().driver_data(); - int x, y, ret; + int ret; +/* if (DISPLAY_TEXTURE && (screen->machine().input().code_pressed(KEYCODE_Z) || screen->machine().input().code_pressed(KEYCODE_X))) { static int xv = 0, yv = 0x1000; @@ -487,10 +473,10 @@ SCREEN_UPDATE( gaelco3d ) } popmessage("(%04X,%04X)", xv, yv); } - else + else*/ { if (state->m_video_changed) - copybitmap(bitmap, state->m_screenbits, 0,1, 0,0, cliprect); + copybitmap(bitmap, state->m_poly->screenbits(), 0,1, 0,0, cliprect); ret = state->m_video_changed; state->m_video_changed = FALSE; } diff --git a/src/mame/video/midvunit.c b/src/mame/video/midvunit.c index 2b18876bbb8..266d2464701 100644 --- a/src/mame/video/midvunit.c +++ b/src/mame/video/midvunit.c @@ -8,7 +8,6 @@ #include "cpu/tms34010/tms34010.h" #include "cpu/adsp2100/adsp2100.h" #include "audio/williams.h" -#include "video/poly.h" #include "includes/midvunit.h" @@ -24,14 +23,9 @@ #define TIME_PER_PIXEL 41e-9 -typedef struct _poly_extra_data poly_extra_data; -struct _poly_extra_data -{ - UINT8 * texbase; - UINT16 pixdata; - UINT8 dither; -}; - +midvunit_renderer::midvunit_renderer(midvunit_state &state) + : poly_manager(state.machine()), + m_state(state) { } /************************************* @@ -56,19 +50,12 @@ static TIMER_CALLBACK( scanline_timer_cb ) } -static void midvunit_exit(running_machine &machine) -{ - midvunit_state *state = machine.driver_data(); - poly_free(state->m_poly); -} - - VIDEO_START( midvunit ) { midvunit_state *state = machine.driver_data(); state->m_scanline_timer = machine.scheduler().timer_alloc(FUNC(scanline_timer_cb)); - state->m_poly = poly_alloc(machine, 4000, sizeof(poly_extra_data), POLYFLAG_ALLOW_QUADS); - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(midvunit_exit), &machine)); + + state->m_poly = auto_alloc(machine, midvunit_renderer(*state)); state_save_register_global_array(machine, state->m_video_regs); state_save_register_global_array(machine, state->m_dma_data); @@ -85,26 +72,25 @@ VIDEO_START( midvunit ) * *************************************/ -static void render_flat(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) +void midvunit_renderer::render_flat(INT32 scanline, const extent_t &extent, const midvunit_object_data &objectdata, int threadid) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - UINT16 pixdata = extra->pixdata; - int xstep = extra->dither + 1; - UINT16 *dest = (UINT16 *)destbase + scanline * 512; - int startx = extent->startx; + UINT16 pixdata = objectdata.pixdata; + int xstep = objectdata.dither + 1; + UINT16 *dest = objectdata.destbase + scanline * 512; + int startx = extent.startx; int x; /* if dithering, ensure that we start on an appropriate pixel */ - startx += (scanline ^ startx) & extra->dither; + startx += (scanline ^ startx) & objectdata.dither; /* non-dithered 0 pixels can use a memset */ if (pixdata == 0 && xstep == 1) - memset(&dest[startx], 0, 2 * (extent->stopx - startx + 1)); + memset(&dest[startx], 0, 2 * (extent.stopx - startx + 1)); /* otherwise, we fill manually */ else { - for (x = startx; x < extent->stopx; x += xstep) + for (x = startx; x < extent.stopx; x += xstep) dest[x] = pixdata; } } @@ -117,19 +103,18 @@ static void render_flat(void *destbase, INT32 scanline, const poly_extent *exten * *************************************/ -static void render_tex(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) +void midvunit_renderer::render_tex(INT32 scanline, const extent_t &extent, const midvunit_object_data &objectdata, int threadid) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - UINT16 pixdata = extra->pixdata & 0xff00; - const UINT8 *texbase = extra->texbase; - int xstep = extra->dither + 1; - UINT16 *dest = (UINT16 *)destbase + scanline * 512; - int startx = extent->startx; - int stopx = extent->stopx; - INT32 u = extent->param[0].start; - INT32 v = extent->param[1].start; - INT32 dudx = extent->param[0].dpdx; - INT32 dvdx = extent->param[1].dpdx; + UINT16 pixdata = objectdata.pixdata & 0xff00; + const UINT8 *texbase = objectdata.texbase; + int xstep = objectdata.dither + 1; + UINT16 *dest = objectdata.destbase + scanline * 512; + int startx = extent.startx; + int stopx = extent.stopx; + INT32 u = extent.param[0].start; + INT32 v = extent.param[1].start; + INT32 dudx = extent.param[0].dpdx; + INT32 dvdx = extent.param[1].dpdx; int x; /* if dithering, we advance by 2x; also ensure that we start on an appropriate pixel */ @@ -155,19 +140,18 @@ static void render_tex(void *destbase, INT32 scanline, const poly_extent *extent } -static void render_textrans(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) +void midvunit_renderer::render_textrans(INT32 scanline, const extent_t &extent, const midvunit_object_data &objectdata, int threadid) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - UINT16 pixdata = extra->pixdata & 0xff00; - const UINT8 *texbase = extra->texbase; - int xstep = extra->dither + 1; - UINT16 *dest = (UINT16 *)destbase + scanline * 512; - int startx = extent->startx; - int stopx = extent->stopx; - INT32 u = extent->param[0].start; - INT32 v = extent->param[1].start; - INT32 dudx = extent->param[0].dpdx; - INT32 dvdx = extent->param[1].dpdx; + UINT16 pixdata = objectdata.pixdata & 0xff00; + const UINT8 *texbase = objectdata.texbase; + int xstep = objectdata.dither + 1; + UINT16 *dest = objectdata.destbase + scanline * 512; + int startx = extent.startx; + int stopx = extent.stopx; + INT32 u = extent.param[0].start; + INT32 v = extent.param[1].start; + INT32 dudx = extent.param[0].dpdx; + INT32 dvdx = extent.param[1].dpdx; int x; /* if dithering, we advance by 2x; also ensure that we start on an appropriate pixel */ @@ -195,19 +179,18 @@ static void render_textrans(void *destbase, INT32 scanline, const poly_extent *e } -static void render_textransmask(void *destbase, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) +void midvunit_renderer::render_textransmask(INT32 scanline, const extent_t &extent, const midvunit_object_data &objectdata, int threadid) { - const poly_extra_data *extra = (const poly_extra_data *)extradata; - UINT16 pixdata = extra->pixdata; - const UINT8 *texbase = extra->texbase; - int xstep = extra->dither + 1; - UINT16 *dest = (UINT16 *)destbase + scanline * 512; - int startx = extent->startx; - int stopx = extent->stopx; - INT32 u = extent->param[0].start; - INT32 v = extent->param[1].start; - INT32 dudx = extent->param[0].dpdx; - INT32 dvdx = extent->param[1].dpdx; + UINT16 pixdata = objectdata.pixdata; + const UINT8 *texbase = objectdata.texbase; + int xstep = objectdata.dither + 1; + UINT16 *dest = objectdata.destbase + scanline * 512; + int startx = extent.startx; + int stopx = extent.stopx; + INT32 u = extent.param[0].start; + INT32 v = extent.param[1].start; + INT32 dudx = extent.param[0].dpdx; + INT32 dvdx = extent.param[1].dpdx; int x; /* if dithering, we advance by 2x; also ensure that we start on an appropriate pixel */ @@ -242,17 +225,15 @@ static void render_textransmask(void *destbase, INT32 scanline, const poly_exten * *************************************/ -static void make_vertices_inclusive(poly_vertex *vert) +void midvunit_renderer::make_vertices_inclusive(vertex_t *vert) { - UINT8 rmask = 0, bmask = 0, eqmask = 0; - int vnum; - /* build up a mask of right and bottom points */ /* note we assume clockwise orientation here */ - for (vnum = 0; vnum < 4; vnum++) + UINT8 rmask = 0, bmask = 0, eqmask = 0; + for (int vnum = 0; vnum < 4; vnum++) { - poly_vertex *currv = &vert[vnum]; - poly_vertex *nextv = &vert[(vnum + 1) & 3]; + vertex_t *currv = &vert[vnum]; + vertex_t *nextv = &vert[(vnum + 1) & 3]; /* if this vertex equals the next one, tag it */ if (nextv->y == currv->y && nextv->x == currv->x) @@ -272,9 +253,9 @@ static void make_vertices_inclusive(poly_vertex *vert) return; /* adjust the right/bottom points so that they get included */ - for (vnum = 0; vnum < 4; vnum++) + for (int vnum = 0; vnum < 4; vnum++) { - poly_vertex *currv = &vert[vnum]; + vertex_t *currv = &vert[vnum]; int effvnum = vnum; /* if we're equal to the next vertex, use that instead */ @@ -290,73 +271,71 @@ static void make_vertices_inclusive(poly_vertex *vert) } -static void process_dma_queue(running_machine &machine) +void midvunit_renderer::process_dma_queue() { - midvunit_state *state = machine.driver_data(); - poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(state->m_poly); - UINT16 *dest = &state->m_videoram[(state->m_page_control & 4) ? 0x40000 : 0x00000]; - int textured = ((state->m_dma_data[0] & 0x300) == 0x100); - poly_draw_scanline_func callback; - poly_vertex vert[4]; - /* if we're rendering to the same page we're viewing, it has changed */ - if ((((state->m_page_control >> 2) ^ state->m_page_control) & 1) == 0 || WATCH_RENDER) - state->m_video_changed = TRUE; + if ((((m_state.m_page_control >> 2) ^ m_state.m_page_control) & 1) == 0 || WATCH_RENDER) + m_state.m_video_changed = TRUE; /* fill in the vertex data */ - vert[0].x = (float)(INT16)state->m_dma_data[2] + 0.5f; - vert[0].y = (float)(INT16)state->m_dma_data[3] + 0.5f; - vert[1].x = (float)(INT16)state->m_dma_data[4] + 0.5f; - vert[1].y = (float)(INT16)state->m_dma_data[5] + 0.5f; - vert[2].x = (float)(INT16)state->m_dma_data[6] + 0.5f; - vert[2].y = (float)(INT16)state->m_dma_data[7] + 0.5f; - vert[3].x = (float)(INT16)state->m_dma_data[8] + 0.5f; - vert[3].y = (float)(INT16)state->m_dma_data[9] + 0.5f; + vertex_t vert[4]; + vert[0].x = (float)(INT16)m_state.m_dma_data[2] + 0.5f; + vert[0].y = (float)(INT16)m_state.m_dma_data[3] + 0.5f; + vert[1].x = (float)(INT16)m_state.m_dma_data[4] + 0.5f; + vert[1].y = (float)(INT16)m_state.m_dma_data[5] + 0.5f; + vert[2].x = (float)(INT16)m_state.m_dma_data[6] + 0.5f; + vert[2].y = (float)(INT16)m_state.m_dma_data[7] + 0.5f; + vert[3].x = (float)(INT16)m_state.m_dma_data[8] + 0.5f; + vert[3].y = (float)(INT16)m_state.m_dma_data[9] + 0.5f; /* make the vertices inclusive of right/bottom points */ make_vertices_inclusive(vert); /* handle flat-shaded quads here */ + render_delegate callback; + bool textured = ((m_state.m_dma_data[0] & 0x300) == 0x100); if (!textured) - callback = render_flat; + callback = render_delegate(FUNC(midvunit_renderer::render_flat), this); /* handle textured quads here */ else { /* if textured, add the texture info */ - vert[0].p[0] = (float)(state->m_dma_data[10] & 0xff) * 65536.0f + 32768.0f; - vert[0].p[1] = (float)(state->m_dma_data[10] >> 8) * 65536.0f + 32768.0f; - vert[1].p[0] = (float)(state->m_dma_data[11] & 0xff) * 65536.0f + 32768.0f; - vert[1].p[1] = (float)(state->m_dma_data[11] >> 8) * 65536.0f + 32768.0f; - vert[2].p[0] = (float)(state->m_dma_data[12] & 0xff) * 65536.0f + 32768.0f; - vert[2].p[1] = (float)(state->m_dma_data[12] >> 8) * 65536.0f + 32768.0f; - vert[3].p[0] = (float)(state->m_dma_data[13] & 0xff) * 65536.0f + 32768.0f; - vert[3].p[1] = (float)(state->m_dma_data[13] >> 8) * 65536.0f + 32768.0f; + vert[0].p[0] = (float)(m_state.m_dma_data[10] & 0xff) * 65536.0f + 32768.0f; + vert[0].p[1] = (float)(m_state.m_dma_data[10] >> 8) * 65536.0f + 32768.0f; + vert[1].p[0] = (float)(m_state.m_dma_data[11] & 0xff) * 65536.0f + 32768.0f; + vert[1].p[1] = (float)(m_state.m_dma_data[11] >> 8) * 65536.0f + 32768.0f; + vert[2].p[0] = (float)(m_state.m_dma_data[12] & 0xff) * 65536.0f + 32768.0f; + vert[2].p[1] = (float)(m_state.m_dma_data[12] >> 8) * 65536.0f + 32768.0f; + vert[3].p[0] = (float)(m_state.m_dma_data[13] & 0xff) * 65536.0f + 32768.0f; + vert[3].p[1] = (float)(m_state.m_dma_data[13] >> 8) * 65536.0f + 32768.0f; /* handle non-masked, non-transparent quads */ - if ((state->m_dma_data[0] & 0xc00) == 0x000) - callback = render_tex; + if ((m_state.m_dma_data[0] & 0xc00) == 0x000) + callback = render_delegate(FUNC(midvunit_renderer::render_tex), this); /* handle non-masked, transparent quads */ - else if ((state->m_dma_data[0] & 0xc00) == 0x800) - callback = render_textrans; + else if ((m_state.m_dma_data[0] & 0xc00) == 0x800) + callback = render_delegate(FUNC(midvunit_renderer::render_textrans), this); /* handle masked, transparent quads */ - else if ((state->m_dma_data[0] & 0xc00) == 0xc00) - callback = render_textransmask; + else if ((m_state.m_dma_data[0] & 0xc00) == 0xc00) + callback = render_delegate(FUNC(midvunit_renderer::render_textransmask), this); /* handle masked, non-transparent quads */ else - callback = render_flat; + callback = render_delegate(FUNC(midvunit_renderer::render_flat), this); } - /* set up the extra data for this triangle */ - extra->texbase = (UINT8 *)state->m_textureram + (state->m_dma_data[14] * 256); - extra->pixdata = state->m_dma_data[1] | (state->m_dma_data[0] & 0x00ff); - extra->dither = ((state->m_dma_data[0] & 0x2000) != 0); + /* set up the object data for this triangle */ + midvunit_object_data &objectdata = object_data_alloc(); + objectdata.destbase = &m_state.m_videoram[(m_state.m_page_control & 4) ? 0x40000 : 0x00000]; + objectdata.texbase = (UINT8 *)m_state.m_textureram + (m_state.m_dma_data[14] * 256); + objectdata.pixdata = m_state.m_dma_data[1] | (m_state.m_dma_data[0] & 0x00ff); + objectdata.dither = ((m_state.m_dma_data[0] & 0x2000) != 0); /* render as a quad */ - poly_render_quad(state->m_poly, dest, &machine.primary_screen->visible_area(), callback, textured ? 2 : 0, &vert[0], &vert[1], &vert[2], &vert[3]); + render_polygon<4>(machine().primary_screen->visible_area(), callback, textured ? 2 : 0, vert); } @@ -391,7 +370,7 @@ READ32_HANDLER( midvunit_dma_trigger_r ) { if (LOG_DMA && space->machine().input().code_pressed(KEYCODE_L)) logerror("%06X:trigger\n", cpu_get_pc(&space->device())); - process_dma_queue(space->machine()); + state->m_poly->process_dma_queue(); state->m_dma_data_index = 0; } return 0; @@ -477,7 +456,7 @@ READ32_HANDLER( midvunit_scanline_r ) WRITE32_HANDLER( midvunit_videoram_w ) { midvunit_state *state = space->machine().driver_data(); - poly_wait(state->m_poly, "Video RAM write"); + state->m_poly->wait("Video RAM write"); if (!state->m_video_changed) { int visbase = (state->m_page_control & 1) ? 0x40000 : 0x00000; @@ -491,7 +470,7 @@ WRITE32_HANDLER( midvunit_videoram_w ) READ32_HANDLER( midvunit_videoram_r ) { midvunit_state *state = space->machine().driver_data(); - poly_wait(state->m_poly, "Video RAM read"); + state->m_poly->wait("Video RAM read"); return state->m_videoram[offset]; } @@ -524,7 +503,7 @@ WRITE32_HANDLER( midvunit_textureram_w ) { midvunit_state *state = space->machine().driver_data(); UINT8 *base = (UINT8 *)state->m_textureram; - poly_wait(state->m_poly, "Texture RAM write"); + state->m_poly->wait("Texture RAM write"); base[offset * 2] = data; base[offset * 2 + 1] = data >> 8; } @@ -552,7 +531,7 @@ SCREEN_UPDATE( midvunit ) int x, y, width, xoffs; UINT32 offset; - poly_wait(state->m_poly, "Refresh Time"); + state->m_poly->wait("Refresh Time"); /* if the video didn't change, indicate as much */ if (!state->m_video_changed)