~ubuntu-branches/ubuntu/raring/mame/raring-proposed

« back to all changes in this revision

Viewing changes to mess/src/emu/video/poly.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach, Jordi Mallach, Emmanuel Kasper
  • Date: 2011-12-19 22:56:27 UTC
  • mfrom: (0.1.2)
  • Revision ID: package-import@ubuntu.com-20111219225627-ub5oga1oys4ogqzm
Tags: 0.144-1
[ Jordi Mallach ]
* Fix syntax errors in DEP5 copyright file (lintian).
* Use a versioned copyright Format specification field.
* Update Vcs-* URLs.
* Move transitional packages to the new metapackages section, and make
  them priority extra.
* Remove references to GNU/Linux and MESS sources from copyright.
* Add build variables for s390x.
* Use .xz tarballs as it cuts 4MB for the upstream sources.
* Add nplayers.ini as a patch. Update copyright file to add CC-BY-SA-3.0.

[ Emmanuel Kasper ]
* New upstream release. Closes: #651538.
* Add Free Desktop compliant png icons of various sizes taken from
  the hydroxygen iconset
* Mess is now built from a new source package, to avoid possible source
  incompatibilities between mame and the mess overlay.
* Mame-tools are not built from the mame source package anymore, but
  from the mess source package

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 
3
 
    poly.c
4
 
 
5
 
    Helper routines for polygon rendering.
6
 
 
7
 
***************************************************************************/
8
 
 
9
 
#include "emu.h"
10
 
#include "poly.h"
11
 
 
12
 
 
13
 
/***************************************************************************
14
 
    DEBUGGING
15
 
***************************************************************************/
16
 
 
17
 
/* keep statistics */
18
 
#define KEEP_STATISTICS                                 0
19
 
 
20
 
/* turn this on to log the reasons for any long waits */
21
 
#define LOG_WAITS                                               0
22
 
 
23
 
/* number of profiling ticks before we consider a wait "long" */
24
 
#define LOG_WAIT_THRESHOLD                              1000
25
 
 
26
 
 
27
 
 
28
 
/***************************************************************************
29
 
    CONSTANTS
30
 
***************************************************************************/
31
 
 
32
 
#define SCANLINES_PER_BUCKET                    8
33
 
#define CACHE_LINE_SIZE                                 64                      /* this is a general guess */
34
 
#define TOTAL_BUCKETS                                   (512 / SCANLINES_PER_BUCKET)
35
 
#define UNITS_PER_POLY                                  (100 / SCANLINES_PER_BUCKET)
36
 
 
37
 
 
38
 
 
39
 
/***************************************************************************
40
 
    TYPE DEFINITIONS
41
 
***************************************************************************/
42
 
 
43
 
/* forward definitions */
44
 
typedef struct _polygon_info polygon_info;
45
 
 
46
 
 
47
 
/* tri_extent describes start/end points for a scanline */
48
 
typedef struct _tri_extent tri_extent;
49
 
struct _tri_extent
50
 
{
51
 
        INT16           startx;                                         /* starting X coordinate (inclusive) */
52
 
        INT16           stopx;                                          /* ending X coordinate (exclusive) */
53
 
};
54
 
 
55
 
 
56
 
/* single set of polygon per-parameter data */
57
 
typedef struct _poly_param poly_param;
58
 
struct _poly_param
59
 
{
60
 
        float           start;                                          /* parameter value at starting X,Y */
61
 
        float           dpdx;                                           /* dp/dx relative to starting X */
62
 
        float           dpdy;                                           /* dp/dy relative to starting Y */
63
 
};
64
 
 
65
 
 
66
 
/* poly edge is used internally for quad rendering */
67
 
typedef struct _poly_edge poly_edge;
68
 
struct _poly_edge
69
 
{
70
 
        poly_edge *                     next;                                   /* next edge in sequence */
71
 
        int                                     index;                                  /* index of this edge */
72
 
        const poly_vertex *     v1;                                             /* pointer to first vertex */
73
 
        const poly_vertex *     v2;                                             /* pointer to second vertex */
74
 
        float                           dxdy;                                   /* dx/dy along the edge */
75
 
        float                           dpdy[MAX_VERTEX_PARAMS];/* per-parameter dp/dy values */
76
 
};
77
 
 
78
 
 
79
 
/* poly section is used internally for quad rendering */
80
 
typedef struct _poly_section poly_section;
81
 
struct _poly_section
82
 
{
83
 
        const poly_edge *       ledge;                                  /* pointer to left edge */
84
 
        const poly_edge *       redge;                                  /* pointer to right edge */
85
 
        float                           ybottom;                                /* bottom of this section */
86
 
};
87
 
 
88
 
 
89
 
/* work_unit_shared is a common set of data shared between tris and quads */
90
 
typedef struct _work_unit_shared work_unit_shared;
91
 
struct _work_unit_shared
92
 
{
93
 
        polygon_info *          polygon;                                /* pointer to polygon */
94
 
        volatile UINT32         count_next;                             /* number of scanlines and index of next item to process */
95
 
        INT16                           scanline;                               /* starting scanline and count */
96
 
        UINT16                          previtem;                               /* index of previous item in the same bucket */
97
 
#ifndef PTR64
98
 
        UINT32                          dummy;                                  /* pad to 16 bytes */
99
 
#endif
100
 
};
101
 
 
102
 
 
103
 
/* tri_work_unit is a triangle-specific work-unit */
104
 
typedef struct _tri_work_unit tri_work_unit;
105
 
struct _tri_work_unit
106
 
{
107
 
        work_unit_shared        shared;                                 /* shared data */
108
 
        tri_extent                      extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */
109
 
};
110
 
 
111
 
 
112
 
/* quad_work_unit is a quad-specific work-unit */
113
 
typedef struct _quad_work_unit quad_work_unit;
114
 
struct _quad_work_unit
115
 
{
116
 
        work_unit_shared        shared;                                 /* shared data */
117
 
        poly_extent                     extent[SCANLINES_PER_BUCKET]; /* array of scanline extents */
118
 
};
119
 
 
120
 
 
121
 
/* work_unit is a union of the two types */
122
 
typedef union _work_unit work_unit;
123
 
union _work_unit
124
 
{
125
 
        work_unit_shared        shared;                                 /* shared data */
126
 
        tri_work_unit           tri;                                    /* triangle work unit */
127
 
        quad_work_unit          quad;                                   /* quad work unit */
128
 
};
129
 
 
130
 
 
131
 
/* polygon_info describes a single polygon, which includes the poly_params */
132
 
struct _polygon_info
133
 
{
134
 
        poly_manager *          poly;                                   /* pointer back to the poly manager */
135
 
        void *                          dest;                                   /* pointer to the destination we are rendering to */
136
 
        void *                          extra;                                  /* extra data pointer */
137
 
        UINT8                           numparams;                              /* number of parameters for this polygon  */
138
 
        UINT8                           numverts;                               /* number of vertices in this polygon */
139
 
        poly_draw_scanline_func         callback;                               /* callback to handle a scanline's worth of work */
140
 
        INT32                           xorigin;                                /* X origin for all parameters */
141
 
        INT32                           yorigin;                                /* Y origin for all parameters */
142
 
        poly_param                      param[MAX_VERTEX_PARAMS];/* array of parameter data */
143
 
};
144
 
 
145
 
 
146
 
/* full poly manager description */
147
 
struct _poly_manager
148
 
{
149
 
        /* queue management */
150
 
        osd_work_queue *        queue;                                  /* work queue */
151
 
 
152
 
        /* triangle work units */
153
 
        work_unit **            unit;                                   /* array of work unit pointers */
154
 
        UINT32                          unit_next;                              /* index of next unit to allocate */
155
 
        UINT32                          unit_count;                             /* number of work units available */
156
 
        size_t                          unit_size;                              /* size of each work unit, in bytes */
157
 
 
158
 
        /* quad work units */
159
 
        UINT32                          quadunit_next;                  /* index of next unit to allocate */
160
 
        UINT32                          quadunit_count;                 /* number of work units available */
161
 
        size_t                          quadunit_size;                  /* size of each work unit, in bytes */
162
 
 
163
 
        /* poly data */
164
 
        polygon_info **         polygon;                                /* array of polygon pointers */
165
 
        UINT32                          polygon_next;                   /* index of next polygon to allocate */
166
 
        UINT32                          polygon_count;                  /* number of polygon items available */
167
 
        size_t                          polygon_size;                   /* size of each polygon, in bytes */
168
 
 
169
 
        /* extra data */
170
 
        void **                         extra;                                  /* array of extra data pointers */
171
 
        UINT32                          extra_next;                             /* index of next extra data to allocate */
172
 
        UINT32                          extra_count;                    /* number of extra data items available */
173
 
        size_t                          extra_size;                             /* size of each extra data, in bytes */
174
 
 
175
 
        /* misc data */
176
 
        UINT8                           flags;                                  /* flags */
177
 
 
178
 
        /* buckets */
179
 
        UINT16                          unit_bucket[TOTAL_BUCKETS]; /* buckets for tracking unit usage */
180
 
 
181
 
        /* statistics */
182
 
        UINT32                          triangles;                              /* number of triangles queued */
183
 
        UINT32                          quads;                                  /* number of quads queued */
184
 
        UINT64                          pixels;                                 /* number of pixels rendered */
185
 
#if KEEP_STATISTICS
186
 
        UINT32                          unit_waits;                             /* number of times we waited for a unit */
187
 
        UINT32                          unit_max;                               /* maximum units used */
188
 
        UINT32                          polygon_waits;                  /* number of times we waited for a polygon */
189
 
        UINT32                          polygon_max;                    /* maximum polygons used */
190
 
        UINT32                          extra_waits;                    /* number of times we waited for an extra data */
191
 
        UINT32                          extra_max;                              /* maximum extra data used */
192
 
        UINT32                          conflicts[WORK_MAX_THREADS]; /* number of conflicts found, per thread */
193
 
        UINT32                          resolved[WORK_MAX_THREADS];     /* number of conflicts resolved, per thread */
194
 
#endif
195
 
};
196
 
 
197
 
 
198
 
 
199
 
/***************************************************************************
200
 
    FUNCTION PROTOTYPES
201
 
***************************************************************************/
202
 
 
203
 
static void **allocate_array(running_machine &machine, size_t *itemsize, UINT32 itemcount);
204
 
static void *poly_item_callback(void *param, int threadid);
205
 
static void poly_state_presave(poly_manager *poly);
206
 
 
207
 
 
208
 
 
209
 
/***************************************************************************
210
 
    INLINE FUNCTIONS
211
 
***************************************************************************/
212
 
 
213
 
/*-------------------------------------------------
214
 
    round_coordinate - round a coordinate to
215
 
    an integer, following rules that 0.5 rounds
216
 
    down
217
 
-------------------------------------------------*/
218
 
 
219
 
INLINE INT32 round_coordinate(float value)
220
 
{
221
 
        INT32 result = floor(value);
222
 
        return result + (value - (float)result > 0.5f);
223
 
}
224
 
 
225
 
 
226
 
/*-------------------------------------------------
227
 
    convert_tri_extent_to_poly_extent - convert
228
 
    a simple tri_extent to a full poly_extent
229
 
-------------------------------------------------*/
230
 
 
231
 
INLINE void convert_tri_extent_to_poly_extent(poly_extent *dstextent, const tri_extent *srcextent, const polygon_info *polygon, INT32 y)
232
 
{
233
 
        /* copy start/stop always */
234
 
        dstextent->startx = srcextent->startx;
235
 
        dstextent->stopx = srcextent->stopx;
236
 
 
237
 
        /* if we have parameters, process them as well */
238
 
        for (int paramnum = 0; paramnum < polygon->numparams; paramnum++)
239
 
        {
240
 
                dstextent->param[paramnum].start = polygon->param[paramnum].start + srcextent->startx * polygon->param[paramnum].dpdx + y * polygon->param[paramnum].dpdy;
241
 
                dstextent->param[paramnum].dpdx = polygon->param[paramnum].dpdx;
242
 
        }
243
 
}
244
 
 
245
 
 
246
 
/*-------------------------------------------------
247
 
    interpolate_vertex - interpolate values in
248
 
    a vertex based on p[0] crossing the clipval
249
 
-------------------------------------------------*/
250
 
 
251
 
INLINE void interpolate_vertex(poly_vertex *outv, const poly_vertex *v1, const poly_vertex *v2, int paramcount, float clipval)
252
 
{
253
 
        float frac = (clipval - v1->p[0]) / (v2->p[0] - v1->p[0]);
254
 
        int paramnum;
255
 
 
256
 
        /* create a new one at the intersection point */
257
 
        outv->x = v1->x + frac * (v2->x - v1->x);
258
 
        outv->y = v1->y + frac * (v2->y - v1->y);
259
 
        for (paramnum = 0; paramnum < paramcount; paramnum++)
260
 
                outv->p[paramnum] = v1->p[paramnum] + frac * (v2->p[paramnum] - v1->p[paramnum]);
261
 
}
262
 
 
263
 
 
264
 
/*-------------------------------------------------
265
 
    copy_vertex - copy vertex data from one to
266
 
    another
267
 
-------------------------------------------------*/
268
 
 
269
 
INLINE void copy_vertex(poly_vertex *outv, const poly_vertex *v, int paramcount)
270
 
{
271
 
        int paramnum;
272
 
 
273
 
        outv->x = v->x;
274
 
        outv->y = v->y;
275
 
        for (paramnum = 0; paramnum < paramcount; paramnum++)
276
 
                outv->p[paramnum] = v->p[paramnum];
277
 
}
278
 
 
279
 
 
280
 
/*-------------------------------------------------
281
 
    allocate_polygon - allocate a new polygon
282
 
    object, blocking if we run out
283
 
-------------------------------------------------*/
284
 
 
285
 
INLINE polygon_info *allocate_polygon(poly_manager *poly, int miny, int maxy)
286
 
{
287
 
        /* wait for a work item if we have to */
288
 
        if (poly->polygon_next + 1 > poly->polygon_count)
289
 
        {
290
 
                poly_wait(poly, "Out of polygons");
291
 
#if KEEP_STATISTICS
292
 
                poly->polygon_waits++;
293
 
#endif
294
 
        }
295
 
        else if (poly->unit_next + (maxy - miny) / SCANLINES_PER_BUCKET + 2 > poly->unit_count)
296
 
        {
297
 
                poly_wait(poly, "Out of work units");
298
 
#if KEEP_STATISTICS
299
 
                poly->unit_waits++;
300
 
#endif
301
 
        }
302
 
#if KEEP_STATISTICS
303
 
        poly->polygon_max = MAX(poly->polygon_max, poly->polygon_next + 1);
304
 
#endif
305
 
        return poly->polygon[poly->polygon_next++];
306
 
}
307
 
 
308
 
 
309
 
 
310
 
/***************************************************************************
311
 
    INITIALIZATION/TEARDOWN
312
 
***************************************************************************/
313
 
 
314
 
/*-------------------------------------------------
315
 
    poly_alloc - initialize a new polygon
316
 
    manager
317
 
-------------------------------------------------*/
318
 
 
319
 
poly_manager *poly_alloc(running_machine &machine, int max_polys, size_t extra_data_size, UINT8 flags)
320
 
{
321
 
        poly_manager *poly;
322
 
 
323
 
        /* allocate the manager itself */
324
 
        poly = auto_alloc_clear(machine, poly_manager);
325
 
        poly->flags = flags;
326
 
 
327
 
        /* allocate polygons */
328
 
        poly->polygon_size = sizeof(polygon_info);
329
 
        poly->polygon_count = MAX(max_polys, 1);
330
 
        poly->polygon_next = 0;
331
 
        poly->polygon = (polygon_info **)allocate_array(machine, &poly->polygon_size, poly->polygon_count);
332
 
 
333
 
        /* allocate extra data */
334
 
        poly->extra_size = extra_data_size;
335
 
        poly->extra_count = poly->polygon_count;
336
 
        poly->extra_next = 1;
337
 
        poly->extra = allocate_array(machine, &poly->extra_size, poly->extra_count);
338
 
 
339
 
        /* allocate triangle work units */
340
 
        poly->unit_size = (flags & POLYFLAG_ALLOW_QUADS) ? sizeof(quad_work_unit) : sizeof(tri_work_unit);
341
 
        poly->unit_count = MIN(poly->polygon_count * UNITS_PER_POLY, 65535);
342
 
        poly->unit_next = 0;
343
 
        poly->unit = (work_unit **)allocate_array(machine, &poly->unit_size, poly->unit_count);
344
 
 
345
 
        /* create the work queue */
346
 
        if (!(flags & POLYFLAG_NO_WORK_QUEUE))
347
 
                poly->queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ);
348
 
 
349
 
        /* request a pre-save callback for synchronization */
350
 
        machine.save().register_presave(save_prepost_delegate(FUNC(poly_state_presave), poly));
351
 
        return poly;
352
 
}
353
 
 
354
 
 
355
 
/*-------------------------------------------------
356
 
    poly_free - free a polygon manager
357
 
-------------------------------------------------*/
358
 
 
359
 
void poly_free(poly_manager *poly)
360
 
{
361
 
#if KEEP_STATISTICS
362
 
{
363
 
        int i, conflicts = 0, resolved = 0;
364
 
        for (i = 0; i < ARRAY_LENGTH(poly->conflicts); i++)
365
 
        {
366
 
                conflicts += poly->conflicts[i];
367
 
                resolved += poly->resolved[i];
368
 
        }
369
 
        printf("Total triangles = %d\n", poly->triangles);
370
 
        printf("Total quads = %d\n", poly->quads);
371
 
        if (poly->pixels > 1000000000)
372
 
                printf("Total pixels   = %d%09d\n", (UINT32)(poly->pixels / 1000000000), (UINT32)(poly->pixels % 1000000000));
373
 
        else
374
 
                printf("Total pixels   = %d\n", (UINT32)poly->pixels);
375
 
        printf("Conflicts:  %d resolved, %d total\n", resolved, conflicts);
376
 
        printf("Units:      %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->unit_max, poly->unit_count, poly->unit_waits, poly->unit_size, poly->unit_count * poly->unit_size);
377
 
        printf("Polygons:   %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->polygon_max, poly->polygon_count, poly->polygon_waits, poly->polygon_size, poly->polygon_count * poly->polygon_size);
378
 
        printf("Extra data: %5d used, %5d allocated, %5d waits, %4d bytes each, %7d total\n", poly->extra_max, poly->extra_count, poly->extra_waits, poly->extra_size, poly->extra_count * poly->extra_size);
379
 
}
380
 
#endif
381
 
 
382
 
        /* free the work queue */
383
 
        if (poly->queue != NULL)
384
 
                osd_work_queue_free(poly->queue);
385
 
}
386
 
 
387
 
 
388
 
 
389
 
/***************************************************************************
390
 
    COMMON FUNCTIONS
391
 
***************************************************************************/
392
 
 
393
 
/*-------------------------------------------------
394
 
    poly_wait - wait for all pending rendering
395
 
    to complete
396
 
-------------------------------------------------*/
397
 
 
398
 
void poly_wait(poly_manager *poly, const char *debug_reason)
399
 
{
400
 
        osd_ticks_t time;
401
 
 
402
 
        /* remember the start time if we're logging */
403
 
        if (LOG_WAITS)
404
 
                time = get_profile_ticks();
405
 
 
406
 
        /* wait for all pending work items to complete */
407
 
        if (poly->queue != NULL)
408
 
                osd_work_queue_wait(poly->queue, osd_ticks_per_second() * 100);
409
 
 
410
 
        /* if we don't have a queue, just run the whole list now */
411
 
        else
412
 
        {
413
 
                int unitnum;
414
 
                for (unitnum = 0; unitnum < poly->unit_next; unitnum++)
415
 
                        poly_item_callback(poly->unit[unitnum], 0);
416
 
        }
417
 
 
418
 
        /* log any long waits */
419
 
        if (LOG_WAITS)
420
 
        {
421
 
                time = get_profile_ticks() - time;
422
 
                if (time > LOG_WAIT_THRESHOLD)
423
 
                        logerror("Poly:Waited %d cycles for %s\n", (int)time, debug_reason);
424
 
        }
425
 
 
426
 
        /* reset the state */
427
 
        poly->polygon_next = poly->unit_next = 0;
428
 
        memset(poly->unit_bucket, 0xff, sizeof(poly->unit_bucket));
429
 
 
430
 
        /* we need to preserve the last extra data that was supplied */
431
 
        if (poly->extra_next > 1)
432
 
                memcpy(poly->extra[0], poly->extra[poly->extra_next - 1], poly->extra_size);
433
 
        poly->extra_next = 1;
434
 
}
435
 
 
436
 
 
437
 
/*-------------------------------------------------
438
 
    poly_get_extra_data - get a pointer to the
439
 
    extra data for the next polygon
440
 
-------------------------------------------------*/
441
 
 
442
 
void *poly_get_extra_data(poly_manager *poly)
443
 
{
444
 
        /* wait for a work item if we have to */
445
 
        if (poly->extra_next + 1 > poly->extra_count)
446
 
        {
447
 
                poly_wait(poly, "Out of extra data");
448
 
#if KEEP_STATISTICS
449
 
                poly->extra_waits++;
450
 
#endif
451
 
        }
452
 
 
453
 
        /* return a pointer to the extra data for the next item */
454
 
#if KEEP_STATISTICS
455
 
        poly->extra_max = MAX(poly->extra_max, poly->extra_next + 1);
456
 
#endif
457
 
        return poly->extra[poly->extra_next++];
458
 
}
459
 
 
460
 
 
461
 
 
462
 
/***************************************************************************
463
 
    CORE TRIANGLE RENDERING
464
 
***************************************************************************/
465
 
 
466
 
/*-------------------------------------------------
467
 
    poly_render_triangle - render a single
468
 
    triangle given 3 vertexes
469
 
-------------------------------------------------*/
470
 
 
471
 
UINT32 poly_render_triangle(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3)
472
 
{
473
 
        float dxdy_v1v2, dxdy_v1v3, dxdy_v2v3;
474
 
        const poly_vertex *tv;
475
 
        INT32 curscan, scaninc;
476
 
        polygon_info *polygon;
477
 
        INT32 v1yclip, v3yclip;
478
 
        INT32 v1y, v3y, v1x;
479
 
        INT32 pixels = 0;
480
 
        UINT32 startunit;
481
 
 
482
 
        /* first sort by Y */
483
 
        if (v2->y < v1->y)
484
 
        {
485
 
                tv = v1;
486
 
                v1 = v2;
487
 
                v2 = tv;
488
 
        }
489
 
        if (v3->y < v2->y)
490
 
        {
491
 
                tv = v2;
492
 
                v2 = v3;
493
 
                v3 = tv;
494
 
                if (v2->y < v1->y)
495
 
                {
496
 
                        tv = v1;
497
 
                        v1 = v2;
498
 
                        v2 = tv;
499
 
                }
500
 
        }
501
 
 
502
 
        /* compute some integral X/Y vertex values */
503
 
        v1x = round_coordinate(v1->x);
504
 
        v1y = round_coordinate(v1->y);
505
 
        v3y = round_coordinate(v3->y);
506
 
 
507
 
        /* clip coordinates */
508
 
        v1yclip = v1y;
509
 
        v3yclip = v3y + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
510
 
        if (cliprect != NULL)
511
 
        {
512
 
                v1yclip = MAX(v1yclip, cliprect->min_y);
513
 
                v3yclip = MIN(v3yclip, cliprect->max_y + 1);
514
 
        }
515
 
        if (v3yclip - v1yclip <= 0)
516
 
                return 0;
517
 
 
518
 
        /* allocate a new polygon */
519
 
        polygon = allocate_polygon(poly, v1yclip, v3yclip);
520
 
 
521
 
        /* fill in the polygon information */
522
 
        polygon->poly = poly;
523
 
        polygon->dest = dest;
524
 
        polygon->callback = callback;
525
 
        polygon->extra = poly->extra[poly->extra_next - 1];
526
 
        polygon->numparams = paramcount;
527
 
        polygon->numverts = 3;
528
 
 
529
 
        /* set the start X/Y coordinates */
530
 
        polygon->xorigin = v1x;
531
 
        polygon->yorigin = v1y;
532
 
 
533
 
        /* compute the slopes for each portion of the triangle */
534
 
        dxdy_v1v2 = (v2->y == v1->y) ? 0.0f : (v2->x - v1->x) / (v2->y - v1->y);
535
 
        dxdy_v1v3 = (v3->y == v1->y) ? 0.0f : (v3->x - v1->x) / (v3->y - v1->y);
536
 
        dxdy_v2v3 = (v3->y == v2->y) ? 0.0f : (v3->x - v2->x) / (v3->y - v2->y);
537
 
 
538
 
        /* compute the X extents for each scanline */
539
 
        startunit = poly->unit_next;
540
 
        for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
541
 
        {
542
 
                UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
543
 
                UINT32 unit_index = poly->unit_next++;
544
 
                tri_work_unit *unit = &poly->unit[unit_index]->tri;
545
 
                int extnum;
546
 
 
547
 
                /* determine how much to advance to hit the next bucket */
548
 
                scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
549
 
 
550
 
                /* fill in the work unit basics */
551
 
                unit->shared.polygon = polygon;
552
 
                unit->shared.count_next = MIN(v3yclip - curscan, scaninc);
553
 
                unit->shared.scanline = curscan;
554
 
                unit->shared.previtem = poly->unit_bucket[bucketnum];
555
 
                poly->unit_bucket[bucketnum] = unit_index;
556
 
 
557
 
                /* iterate over extents */
558
 
                for (extnum = 0; extnum < unit->shared.count_next; extnum++)
559
 
                {
560
 
                        float fully = (float)(curscan + extnum) + 0.5f;
561
 
                        float startx = v1->x + (fully - v1->y) * dxdy_v1v3;
562
 
                        float stopx;
563
 
                        INT32 istartx, istopx;
564
 
 
565
 
                        /* compute the ending X based on which part of the triangle we're in */
566
 
                        if (fully < v2->y)
567
 
                                stopx = v1->x + (fully - v1->y) * dxdy_v1v2;
568
 
                        else
569
 
                                stopx = v2->x + (fully - v2->y) * dxdy_v2v3;
570
 
 
571
 
                        /* clamp to full pixels */
572
 
                        istartx = round_coordinate(startx);
573
 
                        istopx = round_coordinate(stopx);
574
 
 
575
 
                        /* force start < stop */
576
 
                        if (istartx > istopx)
577
 
                        {
578
 
                                INT32 temp = istartx;
579
 
                                istartx = istopx;
580
 
                                istopx = temp;
581
 
                        }
582
 
 
583
 
                        /* include the right edge if requested */
584
 
                        if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE)
585
 
                                istopx++;
586
 
 
587
 
                        /* apply left/right clipping */
588
 
                        if (cliprect != NULL)
589
 
                        {
590
 
                                if (istartx < cliprect->min_x)
591
 
                                        istartx = cliprect->min_x;
592
 
                                if (istopx > cliprect->max_x)
593
 
                                        istopx = cliprect->max_x + 1;
594
 
                        }
595
 
 
596
 
                        /* set the extent and update the total pixel count */
597
 
                        if (istartx >= istopx)
598
 
                                istartx = istopx = 0;
599
 
                        unit->extent[extnum].startx = istartx;
600
 
                        unit->extent[extnum].stopx = istopx;
601
 
                        pixels += istopx - istartx;
602
 
                }
603
 
        }
604
 
#if KEEP_STATISTICS
605
 
        poly->unit_max = MAX(poly->unit_max, poly->unit_next);
606
 
#endif
607
 
 
608
 
        /* compute parameter starting points and deltas */
609
 
        if (paramcount > 0)
610
 
        {
611
 
                float a00 = v2->y - v3->y;
612
 
                float a01 = v3->x - v2->x;
613
 
                float a02 = v2->x*v3->y - v3->x*v2->y;
614
 
                float a10 = v3->y - v1->y;
615
 
                float a11 = v1->x - v3->x;
616
 
                float a12 = v3->x*v1->y - v1->x*v3->y;
617
 
                float a20 = v1->y - v2->y;
618
 
                float a21 = v2->x - v1->x;
619
 
                float a22 = v1->x*v2->y - v2->x*v1->y;
620
 
                float det = a02 + a12 + a22;
621
 
 
622
 
                if(fabsf(det) < 0.001) {
623
 
                        for (int paramnum = 0; paramnum < paramcount; paramnum++)
624
 
                        {
625
 
                                poly_param *params = &polygon->param[paramnum];
626
 
                                params->dpdx = 0;
627
 
                                params->dpdy = 0;
628
 
                                params->start = v1->p[paramnum];
629
 
                        }
630
 
                }
631
 
                else
632
 
                {
633
 
                        float idet = 1/det;
634
 
                        for (int paramnum = 0; paramnum < paramcount; paramnum++)
635
 
                        {
636
 
                                poly_param *params = &polygon->param[paramnum];
637
 
                                params->dpdx  = idet*(v1->p[paramnum]*a00 + v2->p[paramnum]*a10 + v3->p[paramnum]*a20);
638
 
                                params->dpdy  = idet*(v1->p[paramnum]*a01 + v2->p[paramnum]*a11 + v3->p[paramnum]*a21);
639
 
                                params->start = idet*(v1->p[paramnum]*a02 + v2->p[paramnum]*a12 + v3->p[paramnum]*a22);
640
 
                        }
641
 
                }
642
 
        }
643
 
 
644
 
        /* enqueue the work items */
645
 
        if (poly->queue != NULL)
646
 
                osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
647
 
 
648
 
        /* return the total number of pixels in the triangle */
649
 
        poly->triangles++;
650
 
        poly->pixels += pixels;
651
 
        return pixels;
652
 
}
653
 
 
654
 
 
655
 
/*-------------------------------------------------
656
 
    poly_render_triangle_fan - render a set of
657
 
    triangles in a fan
658
 
-------------------------------------------------*/
659
 
 
660
 
UINT32 poly_render_triangle_fan(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v)
661
 
{
662
 
        UINT32 pixels = 0;
663
 
        int vertnum;
664
 
 
665
 
        /* iterate over vertices */
666
 
        for (vertnum = 2; vertnum < numverts; vertnum++)
667
 
                pixels += poly_render_triangle(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum]);
668
 
        return pixels;
669
 
}
670
 
 
671
 
 
672
 
/*-------------------------------------------------
673
 
    poly_render_triangle_custom - perform a custom
674
 
    render of an object, given specific extents
675
 
-------------------------------------------------*/
676
 
 
677
 
UINT32 poly_render_triangle_custom(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline_func callback, int startscanline, int numscanlines, const poly_extent *extents)
678
 
{
679
 
        INT32 curscan, scaninc;
680
 
        polygon_info *polygon;
681
 
        INT32 v1yclip, v3yclip;
682
 
        INT32 pixels = 0;
683
 
        UINT32 startunit;
684
 
 
685
 
        /* clip coordinates */
686
 
        if (cliprect != NULL)
687
 
        {
688
 
                v1yclip = MAX(startscanline, cliprect->min_y);
689
 
                v3yclip = MIN(startscanline + numscanlines, cliprect->max_y + 1);
690
 
        }
691
 
        else
692
 
        {
693
 
                v1yclip = startscanline;
694
 
                v3yclip = startscanline + numscanlines;
695
 
        }
696
 
        if (v3yclip - v1yclip <= 0)
697
 
                return 0;
698
 
 
699
 
        /* allocate a new polygon */
700
 
        polygon = allocate_polygon(poly, v1yclip, v3yclip);
701
 
 
702
 
        /* fill in the polygon information */
703
 
        polygon->poly = poly;
704
 
        polygon->dest = dest;
705
 
        polygon->callback = callback;
706
 
        polygon->extra = poly->extra[poly->extra_next - 1];
707
 
        polygon->numparams = 0;
708
 
        polygon->numverts = 3;
709
 
 
710
 
        /* compute the X extents for each scanline */
711
 
        startunit = poly->unit_next;
712
 
        for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc)
713
 
        {
714
 
                UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
715
 
                UINT32 unit_index = poly->unit_next++;
716
 
                tri_work_unit *unit = &poly->unit[unit_index]->tri;
717
 
                int extnum;
718
 
 
719
 
                /* determine how much to advance to hit the next bucket */
720
 
                scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
721
 
 
722
 
                /* fill in the work unit basics */
723
 
                unit->shared.polygon = polygon;
724
 
                unit->shared.count_next = MIN(v3yclip - curscan, scaninc);
725
 
                unit->shared.scanline = curscan;
726
 
                unit->shared.previtem = poly->unit_bucket[bucketnum];
727
 
                poly->unit_bucket[bucketnum] = unit_index;
728
 
 
729
 
                /* iterate over extents */
730
 
                for (extnum = 0; extnum < unit->shared.count_next; extnum++)
731
 
                {
732
 
                        const poly_extent *extent = &extents[(curscan + extnum) - startscanline];
733
 
                        INT32 istartx = extent->startx, istopx = extent->stopx;
734
 
 
735
 
                        /* force start < stop */
736
 
                        if (istartx > istopx)
737
 
                        {
738
 
                                INT32 temp = istartx;
739
 
                                istartx = istopx;
740
 
                                istopx = temp;
741
 
                        }
742
 
 
743
 
                        /* apply left/right clipping */
744
 
                        if (cliprect != NULL)
745
 
                        {
746
 
                                if (istartx < cliprect->min_x)
747
 
                                        istartx = cliprect->min_x;
748
 
                                if (istopx > cliprect->max_x)
749
 
                                        istopx = cliprect->max_x + 1;
750
 
                        }
751
 
 
752
 
                        /* set the extent and update the total pixel count */
753
 
                        unit->extent[extnum].startx = istartx;
754
 
                        unit->extent[extnum].stopx = istopx;
755
 
                        if (istartx < istopx)
756
 
                                pixels += istopx - istartx;
757
 
                }
758
 
        }
759
 
#if KEEP_STATISTICS
760
 
        poly->unit_max = MAX(poly->unit_max, poly->unit_next);
761
 
#endif
762
 
 
763
 
        /* enqueue the work items */
764
 
        if (poly->queue != NULL)
765
 
                osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
766
 
 
767
 
        /* return the total number of pixels in the object */
768
 
        poly->triangles++;
769
 
        poly->pixels += pixels;
770
 
        return pixels;
771
 
}
772
 
 
773
 
 
774
 
 
775
 
/***************************************************************************
776
 
    CORE QUAD RENDERING
777
 
***************************************************************************/
778
 
 
779
 
/*-------------------------------------------------
780
 
    poly_render_quad - render a single quad
781
 
    given 4 vertexes
782
 
-------------------------------------------------*/
783
 
 
784
 
UINT32 poly_render_quad(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline_func callback, int paramcount, const poly_vertex *v1, const poly_vertex *v2, const poly_vertex *v3, const poly_vertex *v4)
785
 
{
786
 
        poly_edge fedgelist[3], bedgelist[3];
787
 
        const poly_edge *ledge, *redge;
788
 
        const poly_vertex *v[4];
789
 
        poly_edge *edgeptr;
790
 
        int minv, maxv, curv;
791
 
        INT32 minyclip, maxyclip;
792
 
        INT32 miny, maxy;
793
 
        INT32 curscan, scaninc;
794
 
        polygon_info *polygon;
795
 
        INT32 pixels = 0;
796
 
        UINT32 startunit;
797
 
 
798
 
        assert(poly->flags & POLYFLAG_ALLOW_QUADS);
799
 
 
800
 
        /* arrays make things easier */
801
 
        v[0] = v1;
802
 
        v[1] = v2;
803
 
        v[2] = v3;
804
 
        v[3] = v4;
805
 
 
806
 
        /* determine min/max Y vertices */
807
 
        if (v[1]->y < v[0]->y)
808
 
                minv = 1, maxv = 0;
809
 
        else
810
 
                minv = 0, maxv = 1;
811
 
        if (v[2]->y < v[minv]->y)
812
 
                minv = 2;
813
 
        else if (v[2]->y > v[maxv]->y)
814
 
                maxv = 2;
815
 
        if (v[3]->y < v[minv]->y)
816
 
                minv = 3;
817
 
        else if (v[3]->y > v[maxv]->y)
818
 
                maxv = 3;
819
 
 
820
 
        /* determine start/end scanlines */
821
 
        miny = round_coordinate(v[minv]->y);
822
 
        maxy = round_coordinate(v[maxv]->y);
823
 
 
824
 
        /* clip coordinates */
825
 
        minyclip = miny;
826
 
        maxyclip = maxy + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
827
 
        if (cliprect != NULL)
828
 
        {
829
 
                minyclip = MAX(minyclip, cliprect->min_y);
830
 
                maxyclip = MIN(maxyclip, cliprect->max_y + 1);
831
 
        }
832
 
        if (maxyclip - minyclip <= 0)
833
 
                return 0;
834
 
 
835
 
        /* allocate a new polygon */
836
 
        polygon = allocate_polygon(poly, minyclip, maxyclip);
837
 
 
838
 
        /* fill in the polygon information */
839
 
        polygon->poly = poly;
840
 
        polygon->dest = dest;
841
 
        polygon->callback = callback;
842
 
        polygon->extra = poly->extra[poly->extra_next - 1];
843
 
        polygon->numparams = paramcount;
844
 
        polygon->numverts = 4;
845
 
 
846
 
        /* walk forward to build up the forward edge list */
847
 
        edgeptr = &fedgelist[0];
848
 
        for (curv = minv; curv != maxv; curv = (curv + 1) & 3)
849
 
        {
850
 
                int paramnum;
851
 
                float ooy;
852
 
 
853
 
                /* set the two vertices */
854
 
                edgeptr->v1 = v[curv];
855
 
                edgeptr->v2 = v[(curv + 1) & 3];
856
 
 
857
 
                /* if horizontal, skip altogether */
858
 
                if (edgeptr->v1->y == edgeptr->v2->y)
859
 
                        continue;
860
 
 
861
 
                /* need dx/dy always, and parameter deltas as necessary */
862
 
                ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
863
 
                edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
864
 
                for (paramnum = 0; paramnum < paramcount; paramnum++)
865
 
                        edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
866
 
                edgeptr++;
867
 
        }
868
 
 
869
 
        /* walk backward to build up the backward edge list */
870
 
        edgeptr = &bedgelist[0];
871
 
        for (curv = minv; curv != maxv; curv = (curv - 1) & 3)
872
 
        {
873
 
                int paramnum;
874
 
                float ooy;
875
 
 
876
 
                /* set the two vertices */
877
 
                edgeptr->v1 = v[curv];
878
 
                edgeptr->v2 = v[(curv - 1) & 3];
879
 
 
880
 
                /* if horizontal, skip altogether */
881
 
                if (edgeptr->v1->y == edgeptr->v2->y)
882
 
                        continue;
883
 
 
884
 
                /* need dx/dy always, and parameter deltas as necessary */
885
 
                ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
886
 
                edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
887
 
                for (paramnum = 0; paramnum < paramcount; paramnum++)
888
 
                        edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
889
 
                edgeptr++;
890
 
        }
891
 
 
892
 
        /* determine which list is left/right: */
893
 
        /* if the first vertex is shared, compare the slopes */
894
 
        /* if the first vertex is not shared, compare the X coordinates */
895
 
        if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) ||
896
 
                (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x))
897
 
        {
898
 
                ledge = fedgelist;
899
 
                redge = bedgelist;
900
 
        }
901
 
        else
902
 
        {
903
 
                ledge = bedgelist;
904
 
                redge = fedgelist;
905
 
        }
906
 
 
907
 
        /* compute the X extents for each scanline */
908
 
        startunit = poly->unit_next;
909
 
        for (curscan = minyclip; curscan < maxyclip; curscan += scaninc)
910
 
        {
911
 
                UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
912
 
                UINT32 unit_index = poly->unit_next++;
913
 
                quad_work_unit *unit = &poly->unit[unit_index]->quad;
914
 
                int extnum;
915
 
 
916
 
                /* determine how much to advance to hit the next bucket */
917
 
                scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
918
 
 
919
 
                /* fill in the work unit basics */
920
 
                unit->shared.polygon = polygon;
921
 
                unit->shared.count_next = MIN(maxyclip - curscan, scaninc);
922
 
                unit->shared.scanline = curscan;
923
 
                unit->shared.previtem = poly->unit_bucket[bucketnum];
924
 
                poly->unit_bucket[bucketnum] = unit_index;
925
 
 
926
 
                /* iterate over extents */
927
 
                for (extnum = 0; extnum < unit->shared.count_next; extnum++)
928
 
                {
929
 
                        float fully = (float)(curscan + extnum) + 0.5f;
930
 
                        float startx, stopx;
931
 
                        INT32 istartx, istopx;
932
 
                        int paramnum;
933
 
 
934
 
                        /* compute the ending X based on which part of the triangle we're in */
935
 
                        while (fully > ledge->v2->y && fully < v[maxv]->y)
936
 
                                ledge++;
937
 
                        while (fully > redge->v2->y && fully < v[maxv]->y)
938
 
                                redge++;
939
 
                        startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy;
940
 
                        stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy;
941
 
 
942
 
                        /* clamp to full pixels */
943
 
                        istartx = round_coordinate(startx);
944
 
                        istopx = round_coordinate(stopx);
945
 
 
946
 
                        /* compute parameter starting points and deltas */
947
 
                        if (paramcount > 0)
948
 
                        {
949
 
                                float ldy = fully - ledge->v1->y;
950
 
                                float rdy = fully - redge->v1->y;
951
 
                                float oox = 1.0f / (stopx - startx);
952
 
 
953
 
                                /* iterate over parameters */
954
 
                                for (paramnum = 0; paramnum < paramcount; paramnum++)
955
 
                                {
956
 
                                        float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum];
957
 
                                        float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum];
958
 
                                        float dpdx = (rparam - lparam) * oox;
959
 
 
960
 
                                        unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx;
961
 
                                        unit->extent[extnum].param[paramnum].dpdx = dpdx;
962
 
                                }
963
 
                        }
964
 
 
965
 
                        /* include the right edge if requested */
966
 
                        if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE)
967
 
                                istopx++;
968
 
 
969
 
                        /* apply left/right clipping */
970
 
                        if (cliprect != NULL)
971
 
                        {
972
 
                                if (istartx < cliprect->min_x)
973
 
                                {
974
 
                                        for (paramnum = 0; paramnum < paramcount; paramnum++)
975
 
                                                unit->extent[extnum].param[paramnum].start += (cliprect->min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx;
976
 
                                        istartx = cliprect->min_x;
977
 
                                }
978
 
                                if (istopx > cliprect->max_x)
979
 
                                        istopx = cliprect->max_x + 1;
980
 
                        }
981
 
 
982
 
                        /* set the extent and update the total pixel count */
983
 
                        if (istartx >= istopx)
984
 
                                istartx = istopx = 0;
985
 
                        unit->extent[extnum].startx = istartx;
986
 
                        unit->extent[extnum].stopx = istopx;
987
 
                        pixels += istopx - istartx;
988
 
                }
989
 
        }
990
 
#if KEEP_STATISTICS
991
 
        poly->unit_max = MAX(poly->unit_max, poly->unit_next);
992
 
#endif
993
 
 
994
 
        /* enqueue the work items */
995
 
        if (poly->queue != NULL)
996
 
                osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
997
 
 
998
 
        /* return the total number of pixels in the triangle */
999
 
        poly->quads++;
1000
 
        poly->pixels += pixels;
1001
 
        return pixels;
1002
 
}
1003
 
 
1004
 
 
1005
 
/*-------------------------------------------------
1006
 
    poly_render_quad_fan - render a set of
1007
 
    quads in a fan
1008
 
-------------------------------------------------*/
1009
 
 
1010
 
UINT32 poly_render_quad_fan(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v)
1011
 
{
1012
 
        UINT32 pixels = 0;
1013
 
        int vertnum;
1014
 
 
1015
 
        /* iterate over vertices */
1016
 
        for (vertnum = 2; vertnum < numverts; vertnum += 2)
1017
 
                pixels += poly_render_quad(poly, dest, cliprect, callback, paramcount, &v[0], &v[vertnum - 1], &v[vertnum], &v[MIN(vertnum + 1, numverts - 1)]);
1018
 
        return pixels;
1019
 
}
1020
 
 
1021
 
 
1022
 
 
1023
 
/***************************************************************************
1024
 
    CORE POLYGON RENDERING
1025
 
***************************************************************************/
1026
 
 
1027
 
/*-------------------------------------------------
1028
 
    poly_render_polygon - render a single polygon up
1029
 
    to 32 vertices
1030
 
-------------------------------------------------*/
1031
 
 
1032
 
UINT32 poly_render_polygon(poly_manager *poly, void *dest, const rectangle *cliprect, poly_draw_scanline_func callback, int paramcount, int numverts, const poly_vertex *v)
1033
 
{
1034
 
        poly_edge fedgelist[MAX_POLYGON_VERTS - 1], bedgelist[MAX_POLYGON_VERTS - 1];
1035
 
        const poly_edge *ledge, *redge;
1036
 
        poly_edge *edgeptr;
1037
 
        int minv, maxv, curv;
1038
 
        INT32 minyclip, maxyclip;
1039
 
        INT32 miny, maxy;
1040
 
        INT32 curscan, scaninc;
1041
 
        polygon_info *polygon;
1042
 
        INT32 pixels = 0;
1043
 
        UINT32 startunit;
1044
 
        int vertnum;
1045
 
 
1046
 
        assert(poly->flags & POLYFLAG_ALLOW_QUADS);
1047
 
 
1048
 
        /* determine min/max Y vertices */
1049
 
        minv = maxv = 0;
1050
 
        for (vertnum = 1; vertnum < numverts; vertnum++)
1051
 
        {
1052
 
                if (v[vertnum].y < v[minv].y)
1053
 
                        minv = vertnum;
1054
 
                else if (v[vertnum].y > v[maxv].y)
1055
 
                        maxv = vertnum;
1056
 
        }
1057
 
 
1058
 
        /* determine start/end scanlines */
1059
 
        miny = round_coordinate(v[minv].y);
1060
 
        maxy = round_coordinate(v[maxv].y);
1061
 
 
1062
 
        /* clip coordinates */
1063
 
        minyclip = miny;
1064
 
        maxyclip = maxy + ((poly->flags & POLYFLAG_INCLUDE_BOTTOM_EDGE) ? 1 : 0);
1065
 
        if (cliprect != NULL)
1066
 
        {
1067
 
                minyclip = MAX(minyclip, cliprect->min_y);
1068
 
                maxyclip = MIN(maxyclip, cliprect->max_y + 1);
1069
 
        }
1070
 
        if (maxyclip - minyclip <= 0)
1071
 
                return 0;
1072
 
 
1073
 
        /* allocate a new polygon */
1074
 
        polygon = allocate_polygon(poly, minyclip, maxyclip);
1075
 
 
1076
 
        /* fill in the polygon information */
1077
 
        polygon->poly = poly;
1078
 
        polygon->dest = dest;
1079
 
        polygon->callback = callback;
1080
 
        polygon->extra = poly->extra[poly->extra_next - 1];
1081
 
        polygon->numparams = paramcount;
1082
 
        polygon->numverts = numverts;
1083
 
 
1084
 
        /* walk forward to build up the forward edge list */
1085
 
        edgeptr = &fedgelist[0];
1086
 
        for (curv = minv; curv != maxv; curv = (curv == numverts - 1) ? 0 : (curv + 1))
1087
 
        {
1088
 
                int paramnum;
1089
 
                float ooy;
1090
 
 
1091
 
                /* set the two vertices */
1092
 
                edgeptr->v1 = &v[curv];
1093
 
                edgeptr->v2 = &v[(curv == numverts - 1) ? 0 : (curv + 1)];
1094
 
 
1095
 
                /* if horizontal, skip altogether */
1096
 
                if (edgeptr->v1->y == edgeptr->v2->y)
1097
 
                        continue;
1098
 
 
1099
 
                /* need dx/dy always, and parameter deltas as necessary */
1100
 
                ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
1101
 
                edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
1102
 
                for (paramnum = 0; paramnum < paramcount; paramnum++)
1103
 
                        edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
1104
 
                edgeptr++;
1105
 
        }
1106
 
 
1107
 
        /* walk backward to build up the backward edge list */
1108
 
        edgeptr = &bedgelist[0];
1109
 
        for (curv = minv; curv != maxv; curv = (curv == 0) ? (numverts - 1) : (curv - 1))
1110
 
        {
1111
 
                int paramnum;
1112
 
                float ooy;
1113
 
 
1114
 
                /* set the two vertices */
1115
 
                edgeptr->v1 = &v[curv];
1116
 
                edgeptr->v2 = &v[(curv == 0) ? (numverts - 1) : (curv - 1)];
1117
 
 
1118
 
                /* if horizontal, skip altogether */
1119
 
                if (edgeptr->v1->y == edgeptr->v2->y)
1120
 
                        continue;
1121
 
 
1122
 
                /* need dx/dy always, and parameter deltas as necessary */
1123
 
                ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y);
1124
 
                edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy;
1125
 
                for (paramnum = 0; paramnum < paramcount; paramnum++)
1126
 
                        edgeptr->dpdy[paramnum] = (edgeptr->v2->p[paramnum] - edgeptr->v1->p[paramnum]) * ooy;
1127
 
                edgeptr++;
1128
 
        }
1129
 
 
1130
 
        /* determine which list is left/right: */
1131
 
        /* if the first vertex is shared, compare the slopes */
1132
 
        /* if the first vertex is not shared, compare the X coordinates */
1133
 
        if ((fedgelist[0].v1 == bedgelist[0].v1 && fedgelist[0].dxdy < bedgelist[0].dxdy) ||
1134
 
                (fedgelist[0].v1 != bedgelist[0].v1 && fedgelist[0].v1->x < bedgelist[0].v1->x))
1135
 
        {
1136
 
                ledge = fedgelist;
1137
 
                redge = bedgelist;
1138
 
        }
1139
 
        else
1140
 
        {
1141
 
                ledge = bedgelist;
1142
 
                redge = fedgelist;
1143
 
        }
1144
 
 
1145
 
        /* compute the X extents for each scanline */
1146
 
        startunit = poly->unit_next;
1147
 
        for (curscan = minyclip; curscan < maxyclip; curscan += scaninc)
1148
 
        {
1149
 
                UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS;
1150
 
                UINT32 unit_index = poly->unit_next++;
1151
 
                quad_work_unit *unit = &poly->unit[unit_index]->quad;
1152
 
                int extnum;
1153
 
 
1154
 
                /* determine how much to advance to hit the next bucket */
1155
 
                scaninc = SCANLINES_PER_BUCKET - (UINT32)curscan % SCANLINES_PER_BUCKET;
1156
 
 
1157
 
                /* fill in the work unit basics */
1158
 
                unit->shared.polygon = polygon;
1159
 
                unit->shared.count_next = MIN(maxyclip - curscan, scaninc);
1160
 
                unit->shared.scanline = curscan;
1161
 
                unit->shared.previtem = poly->unit_bucket[bucketnum];
1162
 
                poly->unit_bucket[bucketnum] = unit_index;
1163
 
 
1164
 
                /* iterate over extents */
1165
 
                for (extnum = 0; extnum < unit->shared.count_next; extnum++)
1166
 
                {
1167
 
                        float fully = (float)(curscan + extnum) + 0.5f;
1168
 
                        float startx, stopx;
1169
 
                        INT32 istartx, istopx;
1170
 
                        int paramnum;
1171
 
 
1172
 
                        /* compute the ending X based on which part of the triangle we're in */
1173
 
                        while (fully > ledge->v2->y && fully < v[maxv].y)
1174
 
                                ledge++;
1175
 
                        while (fully > redge->v2->y && fully < v[maxv].y)
1176
 
                                redge++;
1177
 
                        startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy;
1178
 
                        stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy;
1179
 
 
1180
 
                        /* clamp to full pixels */
1181
 
                        istartx = round_coordinate(startx);
1182
 
                        istopx = round_coordinate(stopx);
1183
 
 
1184
 
                        /* compute parameter starting points and deltas */
1185
 
                        if (paramcount > 0)
1186
 
                        {
1187
 
                                float ldy = fully - ledge->v1->y;
1188
 
                                float rdy = fully - redge->v1->y;
1189
 
                                float oox = 1.0f / (stopx - startx);
1190
 
 
1191
 
                                /* iterate over parameters */
1192
 
                                for (paramnum = 0; paramnum < paramcount; paramnum++)
1193
 
                                {
1194
 
                                        float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum];
1195
 
                                        float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum];
1196
 
                                        float dpdx = (rparam - lparam) * oox;
1197
 
 
1198
 
                                        unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx;
1199
 
                                        unit->extent[extnum].param[paramnum].dpdx = dpdx;
1200
 
                                }
1201
 
                        }
1202
 
 
1203
 
                        /* include the right edge if requested */
1204
 
                        if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE)
1205
 
                                istopx++;
1206
 
 
1207
 
                        /* apply left/right clipping */
1208
 
                        if (cliprect != NULL)
1209
 
                        {
1210
 
                                if (istartx < cliprect->min_x)
1211
 
                                {
1212
 
                                        for (paramnum = 0; paramnum < paramcount; paramnum++)
1213
 
                                                unit->extent[extnum].param[paramnum].start += (cliprect->min_x - istartx) * unit->extent[extnum].param[paramnum].dpdx;
1214
 
                                        istartx = cliprect->min_x;
1215
 
                                }
1216
 
                                if (istopx > cliprect->max_x)
1217
 
                                        istopx = cliprect->max_x + 1;
1218
 
                        }
1219
 
 
1220
 
                        /* set the extent and update the total pixel count */
1221
 
                        if (istartx >= istopx)
1222
 
                                istartx = istopx = 0;
1223
 
                        unit->extent[extnum].startx = istartx;
1224
 
                        unit->extent[extnum].stopx = istopx;
1225
 
                        pixels += istopx - istartx;
1226
 
                }
1227
 
        }
1228
 
#if KEEP_STATISTICS
1229
 
        poly->unit_max = MAX(poly->unit_max, poly->unit_next);
1230
 
#endif
1231
 
 
1232
 
        /* enqueue the work items */
1233
 
        if (poly->queue != NULL)
1234
 
                osd_work_item_queue_multiple(poly->queue, poly_item_callback, poly->unit_next - startunit, poly->unit[startunit], poly->unit_size, WORK_ITEM_FLAG_AUTO_RELEASE);
1235
 
 
1236
 
        /* return the total number of pixels in the triangle */
1237
 
        poly->quads++;
1238
 
        poly->pixels += pixels;
1239
 
        return pixels;
1240
 
}
1241
 
 
1242
 
 
1243
 
 
1244
 
/***************************************************************************
1245
 
    CLIPPING
1246
 
***************************************************************************/
1247
 
 
1248
 
/*-------------------------------------------------
1249
 
    poly_zclip_if_less - z clip a polygon against
1250
 
    the given value, returning a set of clipped
1251
 
    vertices
1252
 
-------------------------------------------------*/
1253
 
 
1254
 
int poly_zclip_if_less(int numverts, const poly_vertex *v, poly_vertex *outv, int paramcount, float clipval)
1255
 
{
1256
 
        int prevclipped = (v[numverts - 1].p[0] < clipval);
1257
 
        poly_vertex *nextout = outv;
1258
 
        int vertnum;
1259
 
 
1260
 
        /* iterate over vertices */
1261
 
        for (vertnum = 0; vertnum < numverts; vertnum++)
1262
 
        {
1263
 
                int thisclipped = (v[vertnum].p[0] < clipval);
1264
 
 
1265
 
                /* if we switched from clipped to non-clipped, interpolate a vertex */
1266
 
                if (thisclipped != prevclipped)
1267
 
                        interpolate_vertex(nextout++, &v[(vertnum == 0) ? (numverts - 1) : (vertnum - 1)], &v[vertnum], paramcount, clipval);
1268
 
 
1269
 
                /* if this vertex is not clipped, copy it in */
1270
 
                if (!thisclipped)
1271
 
                        copy_vertex(nextout++, &v[vertnum], paramcount);
1272
 
 
1273
 
                /* remember the last state */
1274
 
                prevclipped = thisclipped;
1275
 
        }
1276
 
        return nextout - outv;
1277
 
}
1278
 
 
1279
 
 
1280
 
 
1281
 
/***************************************************************************
1282
 
    INTERNAL FUNCTIONS
1283
 
***************************************************************************/
1284
 
 
1285
 
/*-------------------------------------------------
1286
 
    allocate_array - allocate an array of pointers
1287
 
-------------------------------------------------*/
1288
 
 
1289
 
static void **allocate_array(running_machine &machine, size_t *itemsize, UINT32 itemcount)
1290
 
{
1291
 
        void **ptrarray;
1292
 
        int itemnum;
1293
 
 
1294
 
        /* fail if 0 */
1295
 
        if (itemcount == 0)
1296
 
                return NULL;
1297
 
 
1298
 
        /* round to a cache line boundary */
1299
 
        *itemsize = ((*itemsize + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE;
1300
 
 
1301
 
        /* allocate the array */
1302
 
        ptrarray = auto_alloc_array_clear(machine, void *, itemcount);
1303
 
 
1304
 
        /* allocate the actual items */
1305
 
        ptrarray[0] = auto_alloc_array_clear(machine, UINT8, *itemsize * itemcount);
1306
 
 
1307
 
        /* initialize the pointer array */
1308
 
        for (itemnum = 1; itemnum < itemcount; itemnum++)
1309
 
                ptrarray[itemnum] = (UINT8 *)ptrarray[0] + *itemsize * itemnum;
1310
 
        return ptrarray;
1311
 
}
1312
 
 
1313
 
 
1314
 
/*-------------------------------------------------
1315
 
    poly_item_callback - callback for each poly
1316
 
    item
1317
 
-------------------------------------------------*/
1318
 
 
1319
 
static void *poly_item_callback(void *param, int threadid)
1320
 
{
1321
 
        while (1)
1322
 
        {
1323
 
                work_unit *unit = (work_unit *)param;
1324
 
                polygon_info *polygon = unit->shared.polygon;
1325
 
                int count = unit->shared.count_next & 0xffff;
1326
 
                UINT32 orig_count_next;
1327
 
                int curscan;
1328
 
 
1329
 
                /* if our previous item isn't done yet, enqueue this item to the end and proceed */
1330
 
                if (unit->shared.previtem != 0xffff)
1331
 
                {
1332
 
                        work_unit *prevunit = polygon->poly->unit[unit->shared.previtem];
1333
 
                        if (prevunit->shared.count_next != 0)
1334
 
                        {
1335
 
                                UINT32 unitnum = ((UINT8 *)unit - (UINT8 *)polygon->poly->unit[0]) / polygon->poly->unit_size;
1336
 
                                UINT32 new_count_next;
1337
 
 
1338
 
                                /* attempt to atomically swap in this new value */
1339
 
                                do
1340
 
                                {
1341
 
                                        orig_count_next = prevunit->shared.count_next;
1342
 
                                        new_count_next = orig_count_next | (unitnum << 16);
1343
 
                                } while (compare_exchange32((volatile INT32 *)&prevunit->shared.count_next, orig_count_next, new_count_next) != orig_count_next);
1344
 
 
1345
 
#if KEEP_STATISTICS
1346
 
                                /* track resolved conflicts */
1347
 
                                polygon->poly->conflicts[threadid]++;
1348
 
                                if (orig_count_next != 0)
1349
 
                                        polygon->poly->resolved[threadid]++;
1350
 
#endif
1351
 
                                /* if we succeeded, skip out early so we can do other work */
1352
 
                                if (orig_count_next != 0)
1353
 
                                        break;
1354
 
                        }
1355
 
                }
1356
 
 
1357
 
                /* iterate over extents */
1358
 
                for (curscan = 0; curscan < count; curscan++)
1359
 
                {
1360
 
                        if (polygon->numverts == 3)
1361
 
                        {
1362
 
                                poly_extent tmpextent;
1363
 
                                convert_tri_extent_to_poly_extent(&tmpextent, &unit->tri.extent[curscan], polygon, unit->shared.scanline + curscan);
1364
 
                                (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &tmpextent, polygon->extra, threadid);
1365
 
                        }
1366
 
                        else
1367
 
                                (*polygon->callback)(polygon->dest, unit->shared.scanline + curscan, &unit->quad.extent[curscan], polygon->extra, threadid);
1368
 
                }
1369
 
 
1370
 
                /* set our count to 0 and re-fetch the original count value */
1371
 
                do
1372
 
                {
1373
 
                        orig_count_next = unit->shared.count_next;
1374
 
                } while (compare_exchange32((volatile INT32 *)&unit->shared.count_next, orig_count_next, 0) != orig_count_next);
1375
 
 
1376
 
                /* if we have no more work to do, do nothing */
1377
 
                orig_count_next >>= 16;
1378
 
                if (orig_count_next == 0)
1379
 
                        break;
1380
 
                param = polygon->poly->unit[orig_count_next];
1381
 
        }
1382
 
        return NULL;
1383
 
}
1384
 
 
1385
 
 
1386
 
/*-------------------------------------------------
1387
 
    poly_state_presave - pre-save callback to
1388
 
    ensure everything is synced before saving
1389
 
-------------------------------------------------*/
1390
 
 
1391
 
static void poly_state_presave(poly_manager *poly)
1392
 
{
1393
 
        poly_wait(poly, "pre-save");
1394
 
}