Polygon* clone_polygon(Polygon* polygon) { Polygon* clone = allocate_polygon(polygon->count); memcpy(clone->x, polygon->x, sizeof(float) * polygon->count); memcpy(clone->y, polygon->y, sizeof(float) * polygon->count); return clone; }
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) { INT32 curscan, scaninc; polygon_info *polygon; INT32 v1yclip, v3yclip; INT32 pixels = 0; UINT32 startunit; /* clip coordinates */ v1yclip = MAX(startscanline, cliprect.min_y); v3yclip = MIN(startscanline + numscanlines, cliprect.max_y + 1); if (v3yclip - v1yclip <= 0) return 0; /* allocate a new polygon */ polygon = allocate_polygon(poly, v1yclip, v3yclip); /* fill in the polygon information */ polygon->poly = poly; polygon->dest = dest; polygon->callback = callback; polygon->extra = poly->extra[poly->extra_next - 1]; polygon->numparams = 0; polygon->numverts = 3; /* compute the X extents for each scanline */ startunit = poly->unit_next; for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc) { UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; UINT32 unit_index = poly->unit_next++; tri_work_unit *unit = &poly->unit[unit_index]->tri; int extnum; /* 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->shared.polygon = polygon; unit->shared.count_next = MIN(v3yclip - curscan, scaninc); unit->shared.scanline = curscan; unit->shared.previtem = poly->unit_bucket[bucketnum]; poly->unit_bucket[bucketnum] = unit_index; /* iterate over extents */ for (extnum = 0; extnum < unit->shared.count_next; extnum++) { const poly_extent *extent = &extents[(curscan + extnum) - startscanline]; INT32 istartx = extent->startx, istopx = extent->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 */ unit->extent[extnum].startx = istartx; unit->extent[extnum].stopx = istopx; if (istartx < istopx) pixels += istopx - istartx; } } #if KEEP_STATISTICS poly->unit_max = MAX(poly->unit_max, poly->unit_next); #endif /* enqueue the work items */ if (poly->queue != NULL) 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); /* return the total number of pixels in the object */ poly->triangles++; poly->pixels += pixels; return pixels; }
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) { poly_edge fedgelist[3], bedgelist[3]; const poly_edge *ledge, *redge; const poly_vertex *v[4]; poly_edge *edgeptr; int minv, maxv, curv; INT32 minyclip, maxyclip; INT32 miny, maxy; INT32 curscan, scaninc; polygon_info *polygon; INT32 pixels = 0; UINT32 startunit; assert(poly->flags & POLYFLAG_ALLOW_QUADS); /* arrays make things easier */ v[0] = v1; v[1] = v2; v[2] = v3; v[3] = v4; /* determine min/max Y vertices */ if (v[1]->y < v[0]->y) minv = 1, maxv = 0; else minv = 0, maxv = 1; if (v[2]->y < v[minv]->y) minv = 2; else if (v[2]->y > v[maxv]->y) maxv = 2; if (v[3]->y < v[minv]->y) minv = 3; else if (v[3]->y > v[maxv]->y) maxv = 3; /* determine start/end scanlines */ miny = round_coordinate(v[minv]->y); maxy = round_coordinate(v[maxv]->y); /* clip coordinates */ minyclip = miny; maxyclip = maxy + ((poly->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 = allocate_polygon(poly, minyclip, maxyclip); /* fill in the polygon information */ polygon->poly = poly; polygon->dest = dest; polygon->callback = callback; polygon->extra = poly->extra[poly->extra_next - 1]; polygon->numparams = paramcount; polygon->numverts = 4; /* walk forward to build up the forward edge list */ edgeptr = &fedgelist[0]; for (curv = minv; curv != maxv; curv = (curv + 1) & 3) { int paramnum; float ooy; /* set the two vertices */ edgeptr->v1 = v[curv]; edgeptr->v2 = v[(curv + 1) & 3]; /* if horizontal, skip altogether */ if (edgeptr->v1->y == edgeptr->v2->y) continue; /* need dx/dy always, and parameter deltas as necessary */ ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; for (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 */ edgeptr = &bedgelist[0]; for (curv = minv; curv != maxv; curv = (curv - 1) & 3) { int paramnum; float ooy; /* set the two vertices */ edgeptr->v1 = v[curv]; edgeptr->v2 = v[(curv - 1) & 3]; /* if horizontal, skip altogether */ if (edgeptr->v1->y == edgeptr->v2->y) continue; /* need dx/dy always, and parameter deltas as necessary */ ooy = 1.0f / (edgeptr->v2->y - edgeptr->v1->y); edgeptr->dxdy = (edgeptr->v2->x - edgeptr->v1->x) * ooy; for (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 */ 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 */ startunit = poly->unit_next; for (curscan = minyclip; curscan < maxyclip; curscan += scaninc) { UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; UINT32 unit_index = poly->unit_next++; quad_work_unit *unit = &poly->unit[unit_index]->quad; int extnum; /* 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->shared.polygon = polygon; unit->shared.count_next = MIN(maxyclip - curscan, scaninc); unit->shared.scanline = curscan; unit->shared.previtem = poly->unit_bucket[bucketnum]; poly->unit_bucket[bucketnum] = unit_index; /* iterate over extents */ for (extnum = 0; extnum < unit->shared.count_next; extnum++) { float fully = (float)(curscan + extnum) + 0.5f; float startx, stopx; INT32 istartx, istopx; int paramnum; /* compute the ending X based on which part of the triangle we're in */ while (fully > ledge->v2->y && fully < v[maxv]->y) ledge++; while (fully > redge->v2->y && fully < v[maxv]->y) redge++; startx = ledge->v1->x + (fully - ledge->v1->y) * ledge->dxdy; stopx = redge->v1->x + (fully - redge->v1->y) * redge->dxdy; /* clamp to full pixels */ istartx = round_coordinate(startx); istopx = round_coordinate(stopx); /* compute parameter starting points and deltas */ if (paramcount > 0) { float ldy = fully - ledge->v1->y; float rdy = fully - redge->v1->y; float oox = 1.0f / (stopx - startx); /* iterate over parameters */ for (paramnum = 0; paramnum < paramcount; paramnum++) { float lparam = ledge->v1->p[paramnum] + ldy * ledge->dpdy[paramnum]; float rparam = redge->v1->p[paramnum] + rdy * redge->dpdy[paramnum]; float dpdx = (rparam - lparam) * oox; unit->extent[extnum].param[paramnum].start = lparam;// - ((float)istartx + 0.5f) * dpdx; unit->extent[extnum].param[paramnum].dpdx = dpdx; } } /* include the right edge if requested */ if (poly->flags & POLYFLAG_INCLUDE_RIGHT_EDGE) istopx++; /* apply left/right clipping */ if (istartx < cliprect.min_x) { for (paramnum = 0; paramnum < paramcount; paramnum++) unit->extent[extnum].param[paramnum].start += (cliprect.min_x - istartx) * unit->extent[extnum].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; unit->extent[extnum].startx = istartx; unit->extent[extnum].stopx = istopx; pixels += istopx - istartx; } } #if KEEP_STATISTICS poly->unit_max = MAX(poly->unit_max, poly->unit_next); #endif /* enqueue the work items */ if (poly->queue != NULL) 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); /* return the total number of pixels in the triangle */ poly->quads++; poly->pixels += pixels; return pixels; }
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) { float dxdy_v1v2, dxdy_v1v3, dxdy_v2v3; const poly_vertex *tv; INT32 curscan, scaninc; polygon_info *polygon; INT32 v1yclip, v3yclip; INT32 v1y, v3y, v1x; INT32 pixels = 0; UINT32 startunit; /* first sort by Y */ if (v2->y < v1->y) { tv = v1; v1 = v2; v2 = tv; } if (v3->y < v2->y) { tv = v2; v2 = v3; v3 = tv; if (v2->y < v1->y) { tv = v1; v1 = v2; v2 = tv; } } /* compute some integral X/Y vertex values */ v1x = round_coordinate(v1->x); v1y = round_coordinate(v1->y); v3y = round_coordinate(v3->y); /* clip coordinates */ v1yclip = v1y; v3yclip = v3y + ((poly->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; /* allocate a new polygon */ polygon = allocate_polygon(poly, v1yclip, v3yclip); /* fill in the polygon information */ polygon->poly = poly; polygon->dest = dest; polygon->callback = callback; polygon->extra = poly->extra[poly->extra_next - 1]; polygon->numparams = paramcount; polygon->numverts = 3; /* set the start X/Y coordinates */ polygon->xorigin = v1x; polygon->yorigin = v1y; /* compute the slopes for each portion of the triangle */ dxdy_v1v2 = (v2->y == v1->y) ? 0.0f : (v2->x - v1->x) / (v2->y - v1->y); dxdy_v1v3 = (v3->y == v1->y) ? 0.0f : (v3->x - v1->x) / (v3->y - v1->y); dxdy_v2v3 = (v3->y == v2->y) ? 0.0f : (v3->x - v2->x) / (v3->y - v2->y); /* compute the X extents for each scanline */ startunit = poly->unit_next; for (curscan = v1yclip; curscan < v3yclip; curscan += scaninc) { UINT32 bucketnum = ((UINT32)curscan / SCANLINES_PER_BUCKET) % TOTAL_BUCKETS; UINT32 unit_index = poly->unit_next++; tri_work_unit *unit = &poly->unit[unit_index]->tri; int extnum; /* 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->shared.polygon = polygon; unit->shared.count_next = MIN(v3yclip - curscan, scaninc); unit->shared.scanline = curscan; unit->shared.previtem = poly->unit_bucket[bucketnum]; poly->unit_bucket[bucketnum] = unit_index; /* iterate over extents */ for (extnum = 0; extnum < unit->shared.count_next; extnum++) { float fully = (float)(curscan + extnum) + 0.5f; float startx = v1->x + (fully - v1->y) * dxdy_v1v3; float stopx; INT32 istartx, istopx; /* compute the ending X based on which part of the triangle we're in */ 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 */ istartx = round_coordinate(startx); istopx = round_coordinate(stopx); /* force start < stop */ if (istartx > istopx) { INT32 temp = istartx; istartx = istopx; istopx = temp; } /* include the right edge if requested */ if (poly->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; unit->extent[extnum].startx = istartx; unit->extent[extnum].stopx = istopx; pixels += istopx - istartx; } } #if KEEP_STATISTICS poly->unit_max = MAX(poly->unit_max, poly->unit_next); #endif /* compute parameter starting points and deltas */ if (paramcount > 0) { float a00 = v2->y - v3->y; float a01 = v3->x - v2->x; float a02 = v2->x*v3->y - v3->x*v2->y; float a10 = v3->y - v1->y; float a11 = v1->x - v3->x; float a12 = v3->x*v1->y - v1->x*v3->y; float a20 = v1->y - v2->y; float a21 = v2->x - v1->x; float a22 = v1->x*v2->y - v2->x*v1->y; float det = a02 + a12 + a22; if(fabsf(det) < 0.001) { for (int paramnum = 0; paramnum < paramcount; paramnum++) { poly_param *params = &polygon->param[paramnum]; params->dpdx = 0; params->dpdy = 0; params->start = v1->p[paramnum]; } } else { float idet = 1/det; for (int paramnum = 0; paramnum < paramcount; paramnum++) { poly_param *params = &polygon->param[paramnum]; params->dpdx = idet*(v1->p[paramnum]*a00 + v2->p[paramnum]*a10 + v3->p[paramnum]*a20); params->dpdy = idet*(v1->p[paramnum]*a01 + v2->p[paramnum]*a11 + v3->p[paramnum]*a21); params->start = idet*(v1->p[paramnum]*a02 + v2->p[paramnum]*a12 + v3->p[paramnum]*a22); } } } /* enqueue the work items */ if (poly->queue != NULL) 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); /* return the total number of pixels in the triangle */ poly->triangles++; poly->pixels += pixels; return pixels; }