diff options
| author | 2016-04-23 12:21:53 +0200 | |
|---|---|---|
| committer | 2016-04-23 12:21:53 +0200 | |
| commit | c6a9773e153a6ff02f7be6c8191c35f0dc733a27 (patch) | |
| tree | f200a39c03c01645976f1ea2e6175a5b3fb08c7d /src/devices | |
| parent | 9a3b5d9a7557e34e6f398f3ec703085be25d6370 (diff) | |
move vector to video devices (nw)
Diffstat (limited to 'src/devices')
| -rw-r--r-- | src/devices/video/vector.cpp | 355 | ||||
| -rw-r--r-- | src/devices/video/vector.h | 93 |
2 files changed, 448 insertions, 0 deletions
diff --git a/src/devices/video/vector.cpp b/src/devices/video/vector.cpp new file mode 100644 index 00000000000..e83fc5b190e --- /dev/null +++ b/src/devices/video/vector.cpp @@ -0,0 +1,355 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Oliver,Aaron Giles,Bernd Wiebelt,Allard van der Bas +/****************************************************************************** + * + * vector.c + * + * anti-alias code by Andrew Caldwell + * (still more to add) + * + * 040227 Fixed miny clip scaling which was breaking in mhavoc. AREK + * 010903 added support for direct RGB modes MLR + * 980611 use translucent vectors. Thanks to Peter Hirschberg + * and Neil Bradley for the inspiration. BW + * 980307 added cleverer dirty handling. BW, ASG + * fixed antialias table .ac + * 980221 rewrote anti-alias line draw routine + * added inline assembly multiply fuction for 8086 based machines + * beam diameter added to draw routine + * beam diameter is accurate in anti-alias line draw (Tcosin) + * flicker added .ac + * 980203 moved LBO's routines for drawing into a buffer of vertices + * from avgdvg.c to this location. Scaling is now initialized + * by calling vector_init(...). BW + * 980202 moved out of msdos.c ASG + * 980124 added anti-alias line draw routine + * modified avgdvg.c and sega.c to support new line draw routine + * added two new tables Tinten and Tmerge (for 256 color support) + * added find_color routine to build above tables .ac + * + **************************************************************************** */ + +#include "emu.h" +#include "emuopts.h" +#include "rendutil.h" +#include "vector.h" + + +#define FLT_EPSILON 1E-5 + +#define VECTOR_WIDTH_DENOM 512 + +#define MAX_POINTS 10000 + +#define VECTOR_TEAM \ + "-* Vector Heads *-\n" \ + "Brad Oliver\n" \ + "Aaron Giles\n" \ + "Bernd Wiebelt\n" \ + "Allard van der Bas\n" \ + "Al Kossow (VECSIM)\n" \ + "Hedley Rainnie (VECSIM)\n" \ + "Eric Smith (VECSIM)\n" \ + "Neil Bradley (technical advice)\n" \ + "Andrew Caldwell (anti-aliasing)\n" \ + "- *** -\n" + +float vector_options::s_flicker = 0.0f; +float vector_options::s_beam_width_min = 0.0f; +float vector_options::s_beam_width_max = 0.0f; +float vector_options::s_beam_intensity_weight = 0.0f; + +void vector_options::init(emu_options& options) +{ + s_beam_width_min = options.beam_width_min(); + s_beam_width_max = options.beam_width_max(); + s_beam_intensity_weight = options.beam_intensity_weight(); + s_flicker = options.flicker(); +} + +#if 0 + +#define TEXTURE_LENGTH_BUCKETS 32 +#define TEXTURE_INTENSITY_BUCKETS 4 +#define TEXTURE_WIDTH 16 + +#define MAX_INTENSITY 2 +#define VECTOR_BLEED (0.25f) +#define VECTOR_INT_SCALE (255.0f * 1.5f) + + +struct vector_texture +{ + render_texture * texture; + bitmap_argb32 * bitmap; +}; + +static vector_texture *vectortex[TEXTURE_INTENSITY_BUCKETS][TEXTURE_LENGTH_BUCKETS]; + + +static render_texture *get_vector_texture(float dx, float dy, float intensity) +{ + float length = sqrt(dx * dx + dy * dy); + int lbucket = length * (float)TEXTURE_LENGTH_BUCKETS; + int ibucket = (intensity / (float)MAX_INTENSITY) * (float)TEXTURE_INTENSITY_BUCKETS; + vector_texture *tex; + int height, x, y; + float totalint; + + if (lbucket > TEXTURE_LENGTH_BUCKETS) + lbucket = TEXTURE_LENGTH_BUCKETS; + if (ibucket > TEXTURE_INTENSITY_BUCKETS) + ibucket = TEXTURE_INTENSITY_BUCKETS; + + tex = &vectortex[ibucket][lbucket]; + if (tex->texture != NULL) + return tex->texture; + + height = lbucket * VECTOR_WIDTH_DENOM / TEXTURE_LENGTH_BUCKETS; + tex->bitmap = global_alloc(bitmap_argb32(TEXTURE_WIDTH, height)); + tex->bitmap.fill(rgb_t(0xff,0xff,0xff,0xff)); + + totalint = 1.0f; + for (x = TEXTURE_WIDTH / 2 - 1; x >= 0; x--) + { + int intensity = (int)(totalint * (1.0f - VECTOR_BLEED) * VECTOR_INT_SCALE); + intensity = MIN(255, intensity); + totalint -= (float)intensity * (1.0f / VECTOR_INT_SCALE); + + for (y = 0; y < height; y++) + { + UINT32 *pix; + + pix = (UINT32 *)bitmap.base + y * bitmap.rowpixels + x; + *pix = rgb_t((*pix.a() * intensity) >> 8,0xff,0xff,0xff); + + pix = (UINT32 *)bitmap.base + y * bitmap.rowpixels + (TEXTURE_WIDTH - 1 - x); + *pix = rgb_t((*pix.a() * intensity) >> 8,0xff,0xff,0xff); + } + } + + tex->texture = render_texture_create(); + return tex->texture; +} + +#endif + +#define VCLEAN 0 +#define VDIRTY 1 +#define VCLIP 2 + +// device type definition +const device_type VECTOR = &device_creator<vector_device>; + +vector_device::vector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_video_interface(mconfig, *this), + m_vector_list(nullptr), + m_min_intensity(255), + m_max_intensity(0) +{ +} + +vector_device::vector_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VECTOR, "VECTOR", tag, owner, clock, "vector_device", __FILE__), + device_video_interface(mconfig, *this), + m_vector_list(nullptr), + m_min_intensity(255), + m_max_intensity(0) +{ +} + +void vector_device::device_start() +{ + vector_options::init(machine().options()); + + m_vector_index = 0; + + /* allocate memory for tables */ + m_vector_list = make_unique_clear<point[]>(MAX_POINTS); +} + +/* + * www.dinodini.wordpress.com/2010/04/05/normalized-tunable-sigmoid-functions/ + */ +float vector_device::normalized_sigmoid(float n, float k) +{ + // valid for n and k in range of -1.0 and 1.0 + return (n - n * k) / (k - fabs(n) * 2.0f * k + 1.0f); +} + + +/* + * Adds a line end point to the vertices list. The vector processor emulation + * needs to call this. + */ +void vector_device::add_point(int x, int y, rgb_t color, int intensity) +{ + point *newpoint; + + intensity = MAX(0, MIN(255, intensity)); + + m_min_intensity = intensity > 0 ? MIN(m_min_intensity, intensity) : m_min_intensity; + m_max_intensity = intensity > 0 ? MAX(m_max_intensity, intensity) : m_max_intensity; + + if (vector_options::s_flicker && (intensity > 0)) + { + float random = (float)(machine().rand() & 255) / 255.0f; // random value between 0.0 and 1.0 + + intensity -= (int)(intensity * random * vector_options::s_flicker); + + intensity = MAX(0, MIN(255, intensity)); + } + + newpoint = &m_vector_list[m_vector_index]; + newpoint->x = x; + newpoint->y = y; + newpoint->col = color; + newpoint->intensity = intensity; + newpoint->status = VDIRTY; /* mark identical lines as clean later */ + + m_vector_index++; + if (m_vector_index >= MAX_POINTS) + { + m_vector_index--; + logerror("*** Warning! Vector list overflow!\n"); + } +} + + +/* + * Add new clipping info to the list + */ +void vector_device::add_clip(int x1, int yy1, int x2, int y2) +{ + point *newpoint; + + newpoint = &m_vector_list[m_vector_index]; + newpoint->x = x1; + newpoint->y = yy1; + newpoint->arg1 = x2; + newpoint->arg2 = y2; + newpoint->status = VCLIP; + + m_vector_index++; + if (m_vector_index >= MAX_POINTS) + { + m_vector_index--; + logerror("*** Warning! Vector list overflow!\n"); + } +} + + +/* + * The vector CPU creates a new display list. We save the old display list, + * but only once per refresh. + */ +void vector_device::clear_list(void) +{ + m_vector_index = 0; +} + + +UINT32 vector_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + UINT32 flags = PRIMFLAG_ANTIALIAS(machine().options().antialias() ? 1 : 0) | PRIMFLAG_BLENDMODE(BLENDMODE_ADD) | PRIMFLAG_VECTOR(1); + const rectangle &visarea = screen.visible_area(); + float xscale = 1.0f / (65536 * visarea.width()); + float yscale = 1.0f / (65536 * visarea.height()); + float xoffs = (float)visarea.min_x; + float yoffs = (float)visarea.min_y; + float xratio = xscale / yscale; + float yratio = yscale / xscale; + xratio = (xratio < 1.0f) ? xratio : 1.0f; + yratio = (yratio < 1.0f) ? yratio : 1.0f; + + point *curpoint; + render_bounds clip; + int lastx = 0; + int lasty = 0; + + curpoint = m_vector_list.get(); + + screen.container().empty(); + screen.container().add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(0xff,0x00,0x00,0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_VECTORBUF(1)); + + clip.x0 = clip.y0 = 0.0f; + clip.x1 = clip.y1 = 1.0f; + + for (int i = 0; i < m_vector_index; i++) + { + render_bounds coords; + + if (curpoint->status == VCLIP) + { + coords.x0 = ((float)curpoint->x - xoffs) * xscale; + coords.y0 = ((float)curpoint->y - yoffs) * yscale; + coords.x1 = ((float)curpoint->arg1 - xoffs) * xscale; + coords.y1 = ((float)curpoint->arg2 - yoffs) * yscale; + + clip.x0 = (coords.x0 > 0.0f) ? coords.x0 : 0.0f; + clip.y0 = (coords.y0 > 0.0f) ? coords.y0 : 0.0f; + clip.x1 = (coords.x1 < 1.0f) ? coords.x1 : 1.0f; + clip.y1 = (coords.y1 < 1.0f) ? coords.y1 : 1.0f; + } + else + { + float intensity = (float)curpoint->intensity / 255.0f; + float intensity_weight = normalized_sigmoid(intensity, vector_options::s_beam_intensity_weight); + + // check for static intensity + float beam_width = m_min_intensity == m_max_intensity + ? vector_options::s_beam_width_min + : vector_options::s_beam_width_min + intensity_weight * (vector_options::s_beam_width_max - vector_options::s_beam_width_min); + + // normalize width + beam_width *= 1.0f / (float)VECTOR_WIDTH_DENOM; + + coords.x0 = ((float)lastx - xoffs) * xscale; + coords.y0 = ((float)lasty - yoffs) * yscale; + coords.x1 = ((float)curpoint->x - xoffs) * xscale; + coords.y1 = ((float)curpoint->y - yoffs) * yscale; + + float xdistance = coords.x0 - coords.x1; + float ydistance = coords.y0 - coords.y1; + + // extend zero-length vector line (vector point) by 3/8 beam_width on both sides + if (fabs(xdistance) < FLT_EPSILON && + fabs(ydistance) < FLT_EPSILON) + { + coords.x0 += xratio * beam_width * 0.375f; + coords.y0 += yratio * beam_width * 0.375f; + coords.x1 -= xratio * beam_width * 0.375f; + coords.y1 -= yratio * beam_width * 0.375f; + } + // extend vector line by 3/8 beam_width on both sides + else + { + float length = sqrt(xdistance * xdistance + ydistance * ydistance); + float xdirection = xdistance / length; + float ydirection = ydistance / length; + + coords.x0 += xratio * beam_width * 0.375f * (xdirection / xratio); + coords.y0 += yratio * beam_width * 0.375f * (ydirection / yratio); + coords.x1 -= xratio * beam_width * 0.375f * (xdirection / xratio); + coords.y1 -= yratio * beam_width * 0.375f * (ydirection / yratio); + } + + if (curpoint->intensity != 0 && !render_clip_line(&coords, &clip)) + { + screen.container().add_line( + coords.x0, coords.y0, coords.x1, coords.y1, + beam_width, + (curpoint->intensity << 24) | (curpoint->col & 0xffffff), + flags); + } + + lastx = curpoint->x; + lasty = curpoint->y; + } + + curpoint++; + } + + return 0; +} diff --git a/src/devices/video/vector.h b/src/devices/video/vector.h new file mode 100644 index 00000000000..fceadf3800b --- /dev/null +++ b/src/devices/video/vector.h @@ -0,0 +1,93 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Oliver,Aaron Giles,Bernd Wiebelt,Allard van der Bas +#ifndef __VECTOR__ +#define __VECTOR__ + +#define VECTOR_COLOR111(c) \ + rgb_t(pal1bit((c) >> 2), pal1bit((c) >> 1), pal1bit((c) >> 0)) + +#define VECTOR_COLOR222(c) \ + rgb_t(pal2bit((c) >> 4), pal2bit((c) >> 2), pal2bit((c) >> 0)) + +#define VECTOR_COLOR444(c) \ + rgb_t(pal4bit((c) >> 8), pal4bit((c) >> 4), pal4bit((c) >> 0)) + +class vector_device; + +/* The vertices are buffered here */ +struct point +{ + point() : + x(0), + y(0), + col(0), + intensity(0), + arg1(0), + arg2(0), + status(0) {} + + int x; int y; + rgb_t col; + int intensity; + int arg1; int arg2; /* start/end in pixel array or clipping info */ + int status; /* for dirty and clipping handling */ +}; + +class vector_options +{ +public: + friend class vector_device; + + static float s_flicker; + static float s_beam_width_min; + static float s_beam_width_max; + static float s_beam_intensity_weight; + +protected: + static void init(emu_options& options); +}; + +class vector_device : public device_t, public device_video_interface +{ +public: + // construction/destruction + vector_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + vector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source); + + UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void clear_list(); + + void add_point(int x, int y, rgb_t color, int intensity); + void add_clip(int minx, int miny, int maxx, int maxy); + + void set_flicker(float newval); + float get_flicker(); + + void set_beam_width_min(float newval); + float get_beam_width_min(); + + void set_beam_width_max(float newval); + float get_beam_width_max(); + + void set_beam_intensity_weight(float newval); + float get_beam_intensity_weight(); + + // device-level overrides + virtual void device_start() override; + +private: + std::unique_ptr<point[]> m_vector_list; + int m_vector_index; + int m_min_intensity; + int m_max_intensity; + + float normalized_sigmoid(float n, float k); +}; + +// device type definition +extern const device_type VECTOR; + +#define MCFG_VECTOR_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, VECTOR, 0) + +#endif |
