311 lines
7.4 KiB
C
311 lines
7.4 KiB
C
/*
|
|
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
|
|
*
|
|
* $Id: trigen.c 1.3 1995/02/22 21:53:51 sam Exp $
|
|
* $Locker: $
|
|
*
|
|
* Generic triangle scan converter
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <argstd.h>
|
|
#include <error.h>
|
|
|
|
#include "zb.h"
|
|
#include "fixed.h"
|
|
#include "scalar.h"
|
|
#include "shortcut.h"
|
|
|
|
static char rscid[] = "$Id: trigen.c 1.3 1995/02/22 21:53:51 sam Exp $";
|
|
|
|
#define SCAN_FIXED 0 /* Use fixed(1)/floating(0) point maths for parameter gradients */
|
|
|
|
#define BR_FRACT(x) ((br_fixed_luf) (x))
|
|
#define FIXED_AT_OFFSET(ptr, offset) ( *( ((br_fixed_ls *) ((char *) ptr + offset)) ) )
|
|
|
|
#if SCAN_FIXED
|
|
STATIC br_fixed_ls g_divisor;
|
|
#else
|
|
STATIC float g_divisor;
|
|
#endif
|
|
|
|
STATIC br_fixed_ls pdx, pdy;
|
|
|
|
/*
|
|
* A pointer per component index to the parameter block to use and the offset of the scalar to use
|
|
*/
|
|
STATIC struct {
|
|
struct scan_parameter *param;
|
|
int offset;
|
|
} parameter_info[] = {
|
|
NULL, 0, /* C_X */
|
|
NULL, 0, /* C_Y */
|
|
&zb.pz, offsetof(struct temp_vertex, v[Z]), /* C_Z */
|
|
NULL, 0, /* C_W */
|
|
&zb.pu, offsetof(struct temp_vertex, comp[C_U]), /* C_U */
|
|
&zb.pv, offsetof(struct temp_vertex, comp[C_V]), /* C_V */
|
|
&zb.pi, offsetof(struct temp_vertex, comp[C_I]), /* C_I */
|
|
&zb.pr, offsetof(struct temp_vertex, comp[C_R]), /* C_R */
|
|
&zb.pg, offsetof(struct temp_vertex, comp[C_G]), /* C_G */
|
|
&zb.pb, offsetof(struct temp_vertex, comp[C_B]), /* C_B */
|
|
&zb.pq, offsetof(struct temp_vertex, comp[C_Q]), /* C_Q */
|
|
};
|
|
|
|
|
|
/*
|
|
* Set up the per triangle constants for an interpolated parameter
|
|
*/
|
|
|
|
STATIC void ParameterSetup(struct scan_parameter *param,
|
|
int comp,
|
|
struct temp_vertex *v0,
|
|
struct temp_vertex *v1,
|
|
struct temp_vertex *v2)
|
|
{
|
|
|
|
#if SCAN_FIXED
|
|
|
|
br_fixed_ls dp1, dp2;
|
|
|
|
/* Work out parameter deltas
|
|
*/
|
|
|
|
dp1 = FIXED_AT_OFFSET(v1, comp) - FIXED_AT_OFFSET(v0, comp);
|
|
dp2 = FIXED_AT_OFFSET(v2, comp) - FIXED_AT_OFFSET(v0, comp);
|
|
|
|
/* Work out X, Y gradients of parameter
|
|
*/
|
|
|
|
#if 1
|
|
param->grad_x = BrFixedMul(dp1, zb.main.y) - BrFixedMul(dp2, zb.top.y);
|
|
param->grad_x = BrFixedDiv(param->grad_x, g_divisor);
|
|
|
|
param->grad_y = BrFixedMul(dp2, zb.top.x) - BrFixedMul(dp1, zb.main.x);
|
|
param->grad_y = BrFixedDiv(param->grad_y, g_divisor);
|
|
#else
|
|
param->grad_x = BrFixedMac2Div(dp1, zb.main.y, -dp2, zb.top.y, g_divisor);
|
|
|
|
param->grad_y = BrFixedMac2Div(dp2, zb.top.x, -dp1, zb.main.x, g_divisor);
|
|
#endif
|
|
|
|
#else
|
|
|
|
float dp1, dp2;
|
|
|
|
/* Work out parameter deltas
|
|
*/
|
|
|
|
dp1 = BrFixedToFloat(FIXED_AT_OFFSET(v1, comp) - FIXED_AT_OFFSET(v0, comp));
|
|
dp2 = BrFixedToFloat(FIXED_AT_OFFSET(v2, comp) - FIXED_AT_OFFSET(v0, comp));
|
|
|
|
/* Work out X, Y gradients of parameter
|
|
*/
|
|
|
|
param->grad_x = BrFloatToFixed((dp1 * BrFixedToFloat(zb.main.y)
|
|
- dp2 * BrFixedToFloat(zb.top.y)) * g_divisor);
|
|
|
|
param->grad_y = BrFloatToFixed((dp2 * BrFixedToFloat(zb.top.x)
|
|
- dp1 * BrFixedToFloat(zb.main.x)) * g_divisor);
|
|
#endif
|
|
|
|
/* Initialise starting value of parameter
|
|
*/
|
|
|
|
param->current = FIXED_AT_OFFSET(v0, comp) + BrFixedMul(pdx, param->grad_x)
|
|
+ BrFixedMul(pdy, param->grad_y);
|
|
|
|
/* Initialise per scanline increments
|
|
*/
|
|
|
|
param->d_nocarry = BrFixedToInt(zb.main.grad) * param->grad_x + param->grad_y;
|
|
param->d_carry = param->d_nocarry + param->grad_x;
|
|
}
|
|
|
|
/*
|
|
* Generic triangle scan converter
|
|
*/
|
|
#define SWAP(a,b) {t = a; a = b; b = t;}
|
|
|
|
void BR_ASM_CALL GenericTriangleRender(struct temp_vertex *v0, struct temp_vertex *v1, struct temp_vertex *v2)
|
|
{
|
|
struct temp_vertex tv[3];
|
|
struct temp_vertex *t;
|
|
br_int_32 i,j,m;
|
|
char flag;
|
|
|
|
/*
|
|
* General setup -
|
|
*/
|
|
|
|
/* Sort vertices in Y order
|
|
* XXX Optimise?
|
|
*/
|
|
|
|
if ((v0->v[Y]) > (v1->v[Y]))
|
|
SWAP(v0, v1);
|
|
if ((v0->v[Y]) > (v2->v[Y]))
|
|
SWAP(v0, v2);
|
|
if ((v1->v[Y]) > (v2->v[Y]))
|
|
SWAP(v1, v2);
|
|
|
|
/*
|
|
* Work out starts of each edge
|
|
*/
|
|
zb.main.start = zb.top.start = BrFixedToInt(v0->v[Y]);
|
|
zb.bot.start = BrFixedToInt(v1->v[Y]);
|
|
|
|
/* Work out top and bottom trapezoid heights
|
|
*/
|
|
zb.main.count = BrFixedToInt(v2->v[Y]) - zb.main.start;
|
|
zb.top.count = zb.bot.start - zb.top.start;
|
|
zb.bot.count = BrFixedToInt(v2->v[Y]) - zb.bot.start;
|
|
|
|
/*
|
|
* Ignore zero height triangles
|
|
*/
|
|
|
|
if ((zb.top.count == 0) && (zb.bot.count == 0)) return;
|
|
|
|
/* Work out deltas and gradients along...
|
|
*/
|
|
|
|
/* Top short edge
|
|
*/
|
|
zb.top.x = v1->v[X] - v0->v[X];
|
|
zb.top.y = v1->v[Y] - v0->v[Y];
|
|
|
|
if (zb.top.count)
|
|
zb.top.grad = BrFixedDiv(zb.top.x, zb.top.y);
|
|
|
|
/* Bottom short edge
|
|
*/
|
|
zb.bot.x = v2->v[X] - v1->v[X];
|
|
zb.bot.y = v2->v[Y] - v1->v[Y];
|
|
|
|
if (zb.bot.count)
|
|
zb.bot.grad = BrFixedDiv(zb.bot.x, zb.bot.y);
|
|
|
|
/* Long edge
|
|
*/
|
|
zb.main.x = v2->v[X] - v0->v[X];
|
|
zb.main.y = v2->v[Y] - v0->v[Y];
|
|
zb.main.grad = BrFixedDiv(zb.main.x, zb.main.y);
|
|
|
|
/* Work out divisor for parameter gradient calcs.
|
|
*/
|
|
|
|
#if SCAN_FIXED
|
|
g_divisor = BrFixedMul(zb.top.x, zb.main.y) - BrFixedMul(zb.main.x, zb.top.y);
|
|
if (g_divisor == 0) return;
|
|
#else
|
|
g_divisor = (BrFixedToFloat(zb.top.x) * BrFixedToFloat(zb.main.y)
|
|
- BrFixedToFloat(zb.main.x) * BrFixedToFloat(zb.top.y));
|
|
if (g_divisor == 0.0) return;
|
|
g_divisor = 1.0 / g_divisor;
|
|
#endif
|
|
|
|
/* Initialise bottom X
|
|
*/
|
|
|
|
pdy = S1 - BR_FRACT(v1->v[Y]);
|
|
zb.bot.i = v1->v[X] + BrFixedMul(pdy, zb.bot.grad);
|
|
|
|
/* Initialise main X and top X and remember offset so that params can
|
|
* be initialised as well
|
|
*/
|
|
|
|
pdy = S1 - BR_FRACT(v0->v[Y]);
|
|
zb.main.i = v0->v[X] + BrFixedMul(pdy, zb.main.grad);
|
|
zb.top.i = v0->v[X] + BrFixedMul(pdy, zb.top.grad);
|
|
pdx = (zb.main.i & 0xffff0000) + S1 - v0->v[X];
|
|
|
|
/*
|
|
* Prepare any parameters for perspective correct interpolation
|
|
*/
|
|
if(zb.correct_mask) {
|
|
/*
|
|
* Make temporary copies of the vertices
|
|
*/
|
|
tv[0] = *v0; tv[1] = *v1; tv[2] = *v2;
|
|
v0 = tv+0; v1 = tv+1; v2 = tv+2;
|
|
|
|
for(i=0; i<3; i++) {
|
|
|
|
tv[i].comp[C_Q] = BrFixedDiv(S1, tv[i].comp[C_W]);
|
|
|
|
for(j = C_U, m = zb.correct_mask >> C_U ; m ; j++, m = m >> 1 )
|
|
if(m & 1)
|
|
tv[i].comp[j] = BrFixedMul(tv[i].comp[j], tv[i].comp[C_Q]);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set up parameters for scan convertions
|
|
*/
|
|
for(i = C_Z, m = zb.component_mask >> C_Z ; m ; i++, m = m >> 1 )
|
|
if(m & 1)
|
|
ParameterSetup(parameter_info[i].param, parameter_info[i].offset, v0, v1, v2);
|
|
|
|
/*
|
|
* Scan convert the two trapezoids
|
|
*/
|
|
|
|
zb.trapezoid_render(&zb.top);
|
|
zb.trapezoid_render(&zb.bot);
|
|
}
|
|
|
|
/*
|
|
* Scan the trapezoid betwen two edges, calling zb.pixel_plot for each pixel
|
|
*/
|
|
|
|
/* This macro needs extending if NUM_COMPONENTS in zb.h changes */
|
|
#define SET_PARAMS(a, op, b)\
|
|
{\
|
|
zb.pz.a op zb.pz.b;\
|
|
zb.pu.a op zb.pu.b;\
|
|
zb.pv.a op zb.pv.b;\
|
|
zb.pi.a op zb.pi.b;\
|
|
zb.pr.a op zb.pr.b;\
|
|
zb.pg.a op zb.pg.b;\
|
|
zb.pb.a op zb.pb.b;\
|
|
zb.pq.a op zb.pq.b;\
|
|
}
|
|
|
|
void BR_ASM_CALL GenericTrapezoidRender(struct scan_edge *minor)
|
|
{
|
|
char flag;
|
|
int i;
|
|
int y = minor->start;
|
|
|
|
while (minor->count-- > 0) {
|
|
SET_PARAMS(currentpix, =, current)
|
|
|
|
if (g_divisor >= 0) {
|
|
for(i=BrFixedToInt(zb.main.i); i < BrFixedToInt(minor->i); i++) {
|
|
zb.pixel_render(i, y);
|
|
SET_PARAMS(currentpix, +=, grad_x)
|
|
}
|
|
} else {
|
|
for(i=BrFixedToInt(zb.main.i)-1; i > BrFixedToInt(minor->i)-1; i--) {
|
|
SET_PARAMS(currentpix, -=, grad_x)
|
|
zb.pixel_render(i, y);
|
|
}
|
|
}
|
|
|
|
zb.main.i = BrFixedAddCarry(zb.main.i, zb.main.grad, &flag);
|
|
minor->i += minor->grad;
|
|
|
|
y++;
|
|
|
|
if (flag)
|
|
SET_PARAMS(current, +=, d_carry)
|
|
else
|
|
SET_PARAMS(current, +=, d_nocarry)
|
|
}
|
|
}
|
|
|
|
|