Files
TeslaRel410/sda4/DPL3/VRENDER/GEOMETRY.C
T
CydandClaude Fable 5 db7745fcd0 sda4: commit the Glaze developer hard-drive dump
Un-ignored: the dev drive is the ground truth the restoration and
emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer
source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio
content). Kept in-repo for the pod-owner community.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:41:15 -05:00

665 lines
17 KiB
C++

/*
File geometry.c
Contains the geometry functions which need heavy optimisation
currently compile with -opt 4
Phil Atkin
(c) Division Ltd. 1991
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "pazpl5.h"
#define sqrt(f) sqrtf(f)
#define sin(f) sinf(f)
#define cos(f) cosf(f)
/*{{{ #define copy_row()*/
#define copy_row(s,d) \
sx=*s++; sy=*s++; sz=*s++; sw=*s++; \
*d++=sx; *d++=sy; *d++=sz; *d++=sw
/*}}} */
/*{{{ #define cache_opt_matrix(m)*/
#define cache_opt_matrix(m) \
register float m00=m[0][0]; \
register float m01=m[0][1]; \
register float m02=m[0][2]; \
register float m10=m[1][0]; \
register float m11=m[1][1]; \
register float m12=m[1][2]; \
register float m20=m[2][0]; \
register float m21=m[2][1]; \
register float m22=m[2][2]; \
register float m30=m[3][0]; \
register float m31=m[3][1]; \
register float m32=m[3][2]; \
register float m33=m[3][3]; \
register float sx; \
register float sy; \
register float sz;
/*}}} */
/*{{{ #define cache_full_matrix(m)*/
#define cache_full_matrix(m) \
register float m00=m[0][0]; \
register float m01=m[0][1]; \
register float m02=m[0][2]; \
register float m03=m[0][3]; \
register float m10=m[1][0]; \
register float m11=m[1][1]; \
register float m12=m[1][2]; \
register float m13=m[1][3]; \
register float m20=m[2][0]; \
register float m21=m[2][1]; \
register float m22=m[2][2]; \
register float m23=m[2][3]; \
register float m30=m[3][0]; \
register float m31=m[3][1]; \
register float m32=m[3][2]; \
register float m33=m[3][3]; \
register float sx; \
register float sy; \
register float sz; \
register float sw;
/*}}} */
/*{{{ #define cache_norm_matrix(m)*/
#define cache_norm_matrix(m) \
register float m00=m[0][0]; \
register float m01=m[0][1]; \
register float m02=m[0][2]; \
register float m10=m[1][0]; \
register float m11=m[1][1]; \
register float m12=m[1][2]; \
register float m20=m[2][0]; \
register float m21=m[2][1]; \
register float m22=m[2][2]; \
register float sx; \
register float sy; \
register float sz; \
register float dx; \
register float dy; \
register float dz; \
register float hyp
/*}}} */
/*{{{ #define xform_in_place(s)*/
#define xform_in_place(s) \
sx =*s++; \
sy =*s++; \
sz =*s++; \
*s-- = m33; /* W frig ! */ \
*s-- = (sx*m02) + (sy*m12) + (sz*m22) + m32; \
*s-- = (sx*m01) + (sy*m11) + (sz*m21) + m31; \
*s = (sx*m00) + (sy*m10) + (sz*m20) + m30
/*}}} */
/*{{{ #define xform(s,d)*/
#define xform(s,d) \
sx =*s++; \
sy =*s++; \
sz =*s++; \
*d++ = (sx*m00) + (sy*m10) + (sz*m20) + m30; \
*d++ = (sx*m01) + (sy*m11) + (sz*m21) + m31; \
*d++ = (sx*m02) + (sy*m12) + (sz*m22) + m32; \
*d++ = m33
/*}}} */
/*{{{ #define fullxform(s,d)*/
#define fullxform(s,d) \
sx =*s++; sy =*s++; sz =*s++; sw=*s++; \
*d++ = (sx*m00) + (sy*m10) + (sz*m20) + (sw*m30); \
*d++ = (sx*m01) + (sy*m11) + (sz*m21) + (sw*m31); \
*d++ = (sx*m02) + (sy*m12) + (sz*m22) + (sw*m32); \
*d++ = (sx*m03) + (sy*m13) + (sz*m23) + (sw*m33)
/*}}} */
/*{{{ #define nxform(s,d)*/
#define nxform(s,d) \
sx =*s++; \
sy =*s++; \
sz =*s++; \
dx = (sx*m00) + (sy*m10) + (sz*m20); \
dy = (sx*m01) + (sy*m11) + (sz*m21); \
dz = (sx*m02) + (sy*m12) + (sz*m22); \
hyp= 1.0f/sqrt((dx*dx)+(dy*dy)+(dz*dz)); \
*d++=dx*hyp; *d++=dy*hyp; *d++=dz*hyp
/*}}} */
/*{{{ #define nxform_un_norm(s,d)*/
#define nxform_un_norm(s,d) \
sx =*s++; \
sy =*s++; \
sz =*s++; \
*d++ = (sx*m00) + (sy*m10) + (sz*m20); \
*d++ = (sx*m01) + (sy*m11) + (sz*m21); \
*d++ = (sx*m02) + (sy*m12) + (sz*m22)
/*}}} */
/*{{{ #define dot(d,a,b)*/
#define dot(d,a,b) \
ax=*a++; \
bx=*b++; \
ay=*a++; \
by=*b++; \
az=*a++; \
bz=*b++; \
d=((ax*bx)+(ay*by)+(az*bz))
/*}}} */
/*{{{ #define sdot(d,a,b)*/
#define sdot(d,a,b,cook) \
ax=*a++; \
bx=*b++; \
ay=*a++; \
by=*b++; \
az=*a++; \
bz=*b++; \
d=cook*((ax*bx)+(ay*by)+(az*bz))
/*}}} */
#define solve(point,plane) \
(point[X]*plane[X])+(point[Y]*plane[Y])+(point[Z]*plane[Z])+plane[W]
/*{{{ static float dbl_plane_term ( double ay, double by, double cy,*/
static float dbl_plane_term ( double ay, double by, double cy,
double az, double bz, double cz )
{
double r;
r = (ay*(bz-cz))+(by*(cz-az))+(cy*(az-bz));
return (float) r;
}
/*}}} */
/*{{{ void plane_eqn ( POINT pp, POINT aa, POINT bb, POINT cc )*/
void plane_eqn ( dpl_POINT pp, dpl_POINT aa, dpl_POINT bb, dpl_POINT cc )
{
/* extern float fn_plane_term ( float a, float b, float c, float d, float e, float f ); */
register double ax=(double) aa[dpl_X];
register double ay=(double) aa[dpl_Y];
register double az=(double) aa[dpl_Z];
register double bx=(double) bb[dpl_X];
register double by=(double) bb[dpl_Y];
register double bz=(double) bb[dpl_Z];
register double cx=(double) cc[dpl_X];
register double cy=(double) cc[dpl_Y];
register double cz=(double) cc[dpl_Z];
double t;
pp[dpl_X] = (float) dbl_plane_term (ay,by,cy,az,bz,cz);
pp[dpl_Y] = (float) dbl_plane_term (az,bz,cz,ax,bx,cx);
pp[dpl_Z] = (float) dbl_plane_term (ax,bx,cx,ay,by,cy);
/*
t = -((ax*(by*cz - cy*bz)) +
(bx*(cy*az - ay*cz)) +
(cx*(ay*bz - by*az)));
*/
/* NOTE - we do NOT save the correct plane equation, we negate the
d term, so that our comparison becomes ax + by + c > -d,
*/
t = ((ax*(by*cz - cy*bz)) +
(bx*(cy*az - ay*cz)) +
(cx*(ay*bz - by*az)));
pp[dpl_W]=(float) t;
}
/*}}} */
/*{{{ void for_polystrip_plane_eqns ( VSTRIP *v )*/
void for_polystrip_plane_eqns ( VSTRIP *v )
{
VERTEX *v00, *v0, *v1, *vert;
int n;
v00=v->head;
v0=v00;
v1=v0->next;
vert=v1->next;
for (n=v->vertex_count-2; n>0; n-- ) {
plane_eqn(v0->planeEqn, v00->position, v1->position, vert->position );
v0=v1;
v1=vert;
vert=vert->next;
}
}
/*}}} */
/*{{{ static void for_tristrip_plane_eqns ( VSTRIP *v )*/
static void for_tristrip_plane_eqns ( VSTRIP *v )
{
VERTEX *v0, *v1, *vert;
int i, n;
n = v->vertex_count-2;
v0 = v->head;
v1 = v0->next;
vert= v1->next;
for (i=0; i<n; i++ ) {
if (i&1)
plane_eqn(v0->planeEqn, v0->position, vert->position, v1->position );
else
plane_eqn(v0->planeEqn, v0->position, v1->position, vert->position );
v0 = v1;
v1 = vert;
vert= vert->next;
}
}
/*}}} */
/*{{{ int bbox_plane ( POINT *bound, POINT plane )*/
int bbox_plane ( dpl_POINT *b, dpl_POINT plane )
{
register i, posses=0;
for (i=0; i<8; i++) {
posses+=(((*b)[0]*plane[0])+
((*b)[1]*plane[1])+
((*b)[2]*plane[2])+
plane[3]) > 0.0f;
b++;
}
return posses;
}
/*}}} */
/*{{{ void compute_plane_eqns ( PATCH *p, int backwards )*/
void compute_plane_eqns ( PATCH *p, int backwards )
{
VSTRIP *v;
for (v=p->head; v!=NULL; v=v->next ) {
if (v->strip_type == strip_type_tri)
for_tristrip_plane_eqns(v);
else if (v->strip_type == strip_type_poly)
for_polystrip_plane_eqns(v);
}
}
/*}}} */
/*{{{ void compute_gnorms ( VSTRIP *v )*/
void compute_gnorms ( VSTRIP *v )
{
register VERTEX *vert=v->head;
register int n;
register float x;
register float y;
register float z;
register float hyp;
register float *f;
register float *g;
/* needs fixing for supervision */
if ((v->strip_shade & (strip_shade_smooth | strip_shade_coloured)) != 0)
/* return if smooth OR coloured */
return;
for (n=v->vertex_count-2; n>0; n-- ) {
x=vert->planeEqn[0];
y=vert->planeEqn[1];
z=vert->planeEqn[2];
hyp= sqrt ((x*x)+(y*y)+(z*z));
vert=vert->next;
/* gnorm is in NEXT vertex remember */
vert->normcol[0] = x / hyp;
vert->normcol[1] = y / hyp;
vert->normcol[2] = z / hyp;
}
}
/*}}} */
/*{{{ void compute_patch_gnorms ( PATCH *p )*/
void compute_patch_gnorms ( PATCH *p )
{
VSTRIP *v;
for (v=p->head; v!=NULL; v=v->next)
compute_gnorms (v);
}
/*}}} */
/*{{{ void compute_pmesh_plane_eqns ( PATCH *p, int backwards )*/
void compute_pmesh_plane_eqns ( PATCH *p, int backwards )
{
/*
this function computes plane equations, facet normals, and
if necessary averages these normals into the pmesh vertex normals
*/
extern void quick_renorm ( float *t, float a, float b, float c, float scale );
VSTRIP *verts, *triangles;
VERTEX *vert;
int i, smooth=1;
float x, y, z, hyp;
verts=p->head;
triangles=verts->next;
if ((verts->strip_shade & (strip_shade_smooth | strip_shade_coloured)) != 0)
smooth=0;
else {
verts->strip_shade |= strip_shade_smooth;
verts->normals=1;
}
if (smooth) {
for (i=verts->vertex_count, vert=verts->head; i; i--, vert++ ) {
vert->normcol [0]=0.0f;
vert->normcol [1]=0.0f;
vert->normcol [2]=0.0f;
vert->planeEqn[0]=0.0f;
}
}
for (i=0, vert=triangles->head; vert; i++, vert=vert->next ) {
int *ipos=(int *) vert->position;
VERTEX *va, *vb, *vc;
/* compute a plane equation and a facet normal for this triangle */
va=(VERTEX *) (ipos[0]);
vb=(VERTEX *) (ipos[1]);
vc=(VERTEX *) (ipos[2]);
plane_eqn(vert->planeEqn, va->position, vb->position, vc->position );
if (smooth) {
x=vert->planeEqn[0];
y=vert->planeEqn[1];
z=vert->planeEqn[2];
quick_renorm ( vert->normcol, x, y, z, 1.0f );
x=vert->normcol[0];
y=vert->normcol[1];
z=vert->normcol[2];
va->normcol [0]+=x;
va->normcol [1]+=y;
va->normcol [2]+=z;
va->planeEqn[0]+=1.0f;
vb->normcol [0]+=x;
vb->normcol [1]+=y;
vb->normcol [2]+=z;
vb->planeEqn[0]+=1.0f;
vc->normcol [0]+=x;
vc->normcol [1]+=y;
vc->normcol [2]+=z;
vc->planeEqn[0]+=1.0f;
}
}
if (smooth) {
VERTEX *orig;
/* re-normalize normals into clone list */
for (i=verts->vertex_count,
vert=verts->head; i; i--, vert++ ) {
x=vert->normcol[0];
y=vert->normcol[1];
z=vert->normcol[2];
quick_renorm ( vert->normcol, x, y, z, 1.0f );
}
}
}
/*}}} */
/*{{{ int morph_step ( OBJECT *srca, OBJECT *srcb, OBJECT *dst, float t )*/
static OBJECT *currentA=NULL,
*currentB=NULL,
*currentD=NULL;
static int allowmorph=0;
void morphize ( float *a, float *b, float *d, float t, int n )
{
register float one_minus_t=1.0f-t;
for (; n; n--) {
*d++=t*(*b++) + (one_minus_t)*(*a++);
}
}
int morph_step ( OBJECT *srca, OBJECT *srcb, OBJECT *dst, float t )
{
extern void build_bound ( POINT *bound, POINT mini, POINT maxi );
PATCH *pa, *pb, *pd;
VSTRIP *va, *vb, *vd;
VERTEX *verta, *vertb, *vertd;
register float one_minus_t=1.0f-t;
register int n;
/*{{{ check whether morphing is allowed, fix bounding box*/
if ((currentA != srca) ||
(currentB != srcb) ||
(currentD != dst)) {
POINT pta, ptb, ptd, mini, maxi;
/* check topological consistency */
allowmorph=1;
currentA=srca;
currentB=srca;
currentD=dst;
pa=srca->head, pb=srcb->head, pd=dst->head;
while (pa) {
if (pb == NULL) {
allowmorph=0;
return 0;
}
if (pd == NULL) {
allowmorph=0;
return 0;
}
/* now check each vstrip */
va=pa->head, vb=pb->head, vd=pd->head;
while (va) {
if (pb == NULL) {
allowmorph=0;
return 0;
}
if (pd == NULL) {
allowmorph=0;
return 0;
}
if (va->vertex_count != vb->vertex_count) {
allowmorph=0;
return 0;
}
if (vb->vertex_count != vd->vertex_count) {
allowmorph=0;
return 0;
}
va=va->next;
vb=vb->next;
vd=vd->next;
}
/* now rebound dest patch according to srcA and src B */
memcpy ( pta, &pa->bound[0], sizeof(POINT));
memcpy ( ptb, &pb->bound[0], sizeof(POINT));
if (pta[X] < ptb[X]) mini[X]=pta[X]; else mini[X]=ptb[X];
if (pta[Y] < ptb[Y]) mini[Y]=pta[Y]; else mini[Y]=ptb[Y];
if (pta[Z] < ptb[Z]) mini[Z]=pta[Z]; else mini[Z]=ptb[Z];
memcpy ( pta, &pa->bound[7], sizeof(POINT));
memcpy ( ptb, &pb->bound[7], sizeof(POINT));
if (pta[X] > ptb[X]) maxi[X]=pta[X]; else maxi[X]=ptb[X];
if (pta[Y] > ptb[Y]) maxi[Y]=pta[Y]; else maxi[Y]=ptb[Y];
if (pta[Z] > ptb[Z]) maxi[Z]=pta[Z]; else maxi[Z]=ptb[Z];
build_bound ( pd->bound, mini, maxi );
pa=pa->next;
pb=pb->next;
pd=pd->next;
}
reboundObject ( dst );
}
/*}}} */
/*{{{ fix t*/
if (t<0.0f) t=0.0f;
if (t>1.0f) t=1.0f;
/*}}} */
if (allowmorph) {
/*{{{ morph each destination vertex*/
for (pa=srca->head, pb=srcb->head, pd=dst->head;
pa;
pa=pa->next, pb=pb->next, pd=pd->next ) {
/* morph this patch */
for (va=pa->head, vb=pb->head, vd=pd->head;
va;
va=va->next, vb=vb->next, vd=vd->next ) {
for (verta=va->head, vertb=vb->head, vertd=vd->head, n=va->vertex_count;
n;
n--, verta++, vertb++, vertd++ ) {
register float *fd, *fa, *fb;
fd=&vertd->position[0];
fa=&verta->position[0];
fb=&vertb->position[0];
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
fd=&vertd->normcol[0];
fa=&verta->normcol[0];
fb=&vertb->normcol[0];
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
fd=&vertd->texcoords[0];
fa=&verta->texcoords[0];
fb=&vertb->texcoords[0];
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
*fd++=t*(*fb++) + (one_minus_t)*(*fa++);
}
}
compute_plane_eqns ( pd, 0 );
compute_patch_gnorms ( pd );
}
/*}}} */
}
return allowmorph;
}
/*}}} */
/*{{{ void project_points ( float *p, VIEW *eye, int n_points, int stride )*/
void project_points ( float *p, cull_VIEW *eye, int n_points, int stride )
{
/*
all projections now go thru this, relying on the contiguity of vertices
*/
extern float sub_pxl_correct;
int n, i;
float Czscale=1.04857588E+06f;
register float john_rhoades=sub_pxl_correct;
register float px, py, pz, invz, shx, shy, wx, wy, wz, zscale;
wx=eye->screen_half_width;
wy=eye->screen_half_height;
shx=wx*(eye->shift_x+1.0f);
shy=wy*(eye->shift_y+1.0f);
/* is this totally bogus ? */
/* need to compute near/z - then at z=near, z=1, at z=inf, z=0 */
wz=eye->zscale;
for ( n=n_points; n; n-- ) {
invz=eye->d/p[2];
px=((p[0]*wx*invz)+shx)+john_rhoades;
py=((p[1]*wy*invz)+shy)+john_rhoades;
pz=wz*invz*Czscale;
p[0] = px-john_rhoades;
p[1] = py-john_rhoades;
p[2] = pz;
p+=stride;
}
}
/*}}} */
/*{{{ void project_spheres ( float *p, VIEW *eye, int n_points, int stride )*/
void project_spheres ( float *p, cull_VIEW *eye, int n_points, int stride,
float scale_fac )
{
/*
all projections now go thru this, relying on the contiguity of vertices
*/
extern float sub_pxl_correct;
int n, i;
float Czscale=1.04857588E+06f;
register float john_rhoades=sub_pxl_correct;
register float px, py, pz, pr, invz, shx, shy, wx, wy, wz, zscale;
wx=eye->screen_half_width;
wy=eye->screen_half_height;
shx=wx*(eye->shift_x+1.0f);
shy=wy*(eye->shift_y+1.0f);
/* need to compute near/z - then at z=near, z=1, at z=inf, z=0 */
wz=Czscale * eye->zscale;
for ( n=n_points; n; n-- ) {
/* r = radius*xrat*zci; */
/* rz = radius*hithp*dglob->zres/(ze*(ze-radius)); */
pz=p[2];
invz=eye->d/pz;
pr=p[3];
px=((p[0]*wx*invz)+shx)+john_rhoades;
py=((p[1]*wy*invz)+shy)+john_rhoades;
p[0] = px-john_rhoades;
p[1] = py-john_rhoades;
p[2] = wz*invz;
p[3] = scale_fac*pr*wx*invz;
/* planeEqn[3] = z-space screen radius */
p[7] = (pr * wz) / (pz * (pz - pr));
p+=stride;
}
}
/*}}} */