Files
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

1541 lines
39 KiB
C++

/*{{{ banner*/
/* **************************************************
Copyright DIVISION Limited (c) 1994
All rights reserved
File : vr_cull.c
Project : dpl interface / velocirender
Author : PJA
Date : 14/07/94
Function: Implements the cull pass of v-render
The current scene is culled, and renderable
geogroups are assembled into a list to be passed
to the draw pass
History : Rev 1.1, 14 / 07 / 1994
**************************** */
/*}}} */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "dpltypes.h"
#include "culltype.h"
#include "matrix.h"
#include "pxpl5sup\divpxmap.h"
#include "texture.h"
/*{{{ printf_matrix ( dpl_MATRIX m )*/
void
printf_matrix ( dpl_MATRIX m )
{
int i=0;
printf (" [ %f, %f, %f, %f ]\n", m[i][0], m[i][1], m[i][2], m[i][3] );
i=1;
printf (" [ %f, %f, %f, %f ]\n", m[i][0], m[i][1], m[i][2], m[i][3] );
i=2;
printf (" [ %f, %f, %f, %f ]\n", m[i][0], m[i][1], m[i][2], m[i][3] );
i=3;
printf (" [ %f, %f, %f, %f ]\n", m[i][0], m[i][1], m[i][2], m[i][3] );
}
/*}}} */
/*{{{ some statics for culling*/
static dpl_MATERIAL *f_mtl_override;
static dpl_MATERIAL *b_mtl_override;
static dpl_TEXTURE *f_tex_override;
static dpl_TEXTURE *b_tex_override;
static float sphere_scale;
int current_frame_count=0;
int allocated_ramps=0;
dpl_RAMP *ref_texture_ramps[MAX_TEX_RAMPS];
cull_RAMP texture_ramps[MAX_TEX_RAMPS];
/*{{{ 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 compute_plane_eqn ( dpl_POINT pp, dpl_POINT aa, dpl_POINT bb, dpl_POINT cc )*/
void compute_plane_eqn ( dpl_POINT pp, dpl_POINT aa, dpl_POINT bb, dpl_POINT cc )
{
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 - previously we did NOT save the correct plane equation, we negated
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;
}
/*}}} */
/*}}} */
/*{{{ static void cull_view ( cull_VIEW *v, dpl_VIEW *dv )*/
static void cull_view ( cull_VIEW *v, dpl_VIEW *dv )
{
dpl_POINT a, b, c;
float Czscale_eye_d;
extern float Czscale;
extern float eof_FOG_near,
eof_FOG_far;
extern int eof_Z_near,
eof_Z_far,
eof_farZ;
/*
v->aspect_ratio=(dv->x1 - dv->x0) /
(dv->y1 - dv->y0);
*/
v->aspect_ratio=dv->x_size / dv->y_size;
v->d = 2.0f * dv->zeye /
(dv->y1 - dv->y0);
memcpy ( v->f, dv->matrix, sizeof(dpl_MATRIX) );
dpl_Invert ( v->b, v->f );
v->yon = dv->yon_clip;
v->hither = dv->hither_clip;
v->screen_width = dv->x_size;
v->screen_height = dv->y_size;
v->screen_half_width = dv->x_size/2;
v->screen_half_height = dv->y_size/2;
v->shift_x=0;
v->shift_y=0;
v->zscale =v->hither / v->d;
v->zmin =v->hither / v->yon;
v->zmunge = 1.0f /
(1.0f - v->zmin);
a[dpl_X]= 0; a[dpl_Y]= 0; a[dpl_Z]= 0;
b[dpl_X]= dv->x1; b[dpl_Y]= dv->y1; b[dpl_Z]= dv->zeye;
c[dpl_X]= dv->x1; c[dpl_Y]= dv->y0; c[dpl_Z]= dv->zeye;
compute_plane_eqn ( v->plane_x1, a, b, c );
c[dpl_X]=dv->x0; c[dpl_Y]=dv->y1;
compute_plane_eqn ( v->plane_y1, a, c, b );
b[dpl_X]=dv->x0; b[dpl_Y]=dv->y0;
compute_plane_eqn ( v->plane_x0, a, b, c );
c[dpl_X]=dv->x1; c[dpl_Y]=dv->y0;
compute_plane_eqn ( v->plane_y0, a, c, b );
Czscale_eye_d = v->d*v->zscale*Czscale;
eof_Z_far = Czscale_eye_d / eof_FOG_far;
eof_Z_near = Czscale_eye_d / eof_FOG_near;
eof_farZ = Czscale_eye_d / v->yon;
/* printf ("clip planes %f %f\n", v->hither, v->yon ); */
}
/*}}} */
/*{{{ allocation of displaylist structures*/
static ggroup_render_chunk *chunk_head =NULL;
static ggroup_render_chunk *chunk_active=NULL;
static char *chunk_free_ptr=NULL;
static int32 chunk_usage=0;
/*{{{ static void *new_draw_item ( int bump_val )*/
static void *new_draw_item ( int bump_val, dpl_type dpltype )
{
char *cp;
if ((chunk_usage+bump_val)>=MAX_GEOGROUP_USAGE) {
/*{{{ grab a newy*/
if (chunk_active->next == NULL) {
chunk_active->next=(ggroup_render_chunk *) malloc(4096);
if (chunk_active->next==NULL) {
printf ("Velocirender ran out of memory in new_draw_item\n" );
return NULL;
}
chunk_active->next->next=NULL;
}
chunk_active->terminal=0;
chunk_active=chunk_active->next;
chunk_active->terminal=1;
chunk_active->ggroup_count=0;
chunk_free_ptr=&chunk_active->ggroup_data[0];
chunk_usage=0;
/*}}} */
}
cp=chunk_free_ptr;
chunk_usage+=bump_val;
chunk_free_ptr=cp+bump_val;
chunk_active->ggroup_count++;
*((dpl_type *) cp) = dpltype;
return cp;
}
/*}}} */
/*}}} */
/*{{{ static int bbox_plane ( POINT *bound, POINT plane )*/
static int bbox_plane ( dpl_POINT *bound, dpl_POINT plane )
{
/*
this produces impressive-looking compiler output, i dont know
how fast it is though
*/
register int i, code=0;
register float *p=(float *) bound;
register float pA, pB, pC, pD, x, y, z;
pA=plane[0];
pB=plane[1];
pC=plane[2];
pD=plane[3];
for (i=0; i<2; i++) {
x=p[0]; y=p[1]; z=p[2]; p+=4;
code+=(((pA*x) + (pB*y) + (pC*z) + pD)>0);
x=p[0]; y=p[1]; z=p[2]; p+=4;
code+=(((pA*x) + (pB*y) + (pC*z) + pD)>0);
x=p[0]; y=p[1]; z=p[2]; p+=4;
code+=(((pA*x) + (pB*y) + (pC*z) + pD)>0);
x=p[0]; y=p[1]; z=p[2]; p+=4;
code+=(((pA*x) + (pB*y) + (pC*z) + pD)>0);
}
return (code);
}
/*}}} */
/*{{{ static float scale_from_matrix ( MATRIX m )*/
static float scale_from_matrix ( dpl_MATRIX m )
{
float dx, dy, dz;
dx=m[2][0];
dy=m[2][1];
dz=m[2][2];
return (float) sqrt ((dx*dx) + (dy*dy) + (dz*dz));
}
/*}}} */
/*{{{ static int visibility ( dpl_POINT *bound, cull_VIEW *v )*/
static int visibility ( dpl_POINT *bound, cull_VIEW *v )
{
/*
we are performing these visibility checks in WORLD space -
we are checking a frustum, eye at 0,0,0 extending along the -z axis ...
*/
#define triv_posses 8
#define accept_posses 0
register int posses, code=0, i;
/*
printf ("visibility, bound = \n" );
for (i=0; i<8; i++ )
printf ( "[%f,%f,%f]\n",
bound[i][0], bound[i][1], bound[i][2] );
*/
{
dpl_POINT *check;
register float minz, maxz, pz, hith=v->hither, yo=v->yon;
/*{{{ find min+max*/
check=bound;
pz=(*check)[dpl_Z];
minz=pz;
maxz=minz;
/*{{{ 1*/
check++;
pz=(*check)[dpl_Z];
if (pz<minz) minz=pz;
else if (pz>maxz) maxz=pz;
/*}}} */
/*{{{ 2*/
check++;
pz=(*check)[dpl_Z];
if (pz<minz) minz=pz;
else if (pz>maxz) maxz=pz;
/*}}} */
/*{{{ 3*/
check++;
pz=(*check)[dpl_Z];
if (pz<minz) minz=pz;
else if (pz>maxz) maxz=pz;
/*}}} */
/*{{{ 4*/
check++;
pz=(*check)[dpl_Z];
if (pz<minz) minz=pz;
else if (pz>maxz) maxz=pz;
/*}}} */
/*{{{ 5*/
check++;
pz=(*check)[dpl_Z];
if (pz<minz) minz=pz;
else if (pz>maxz) maxz=pz;
/*}}} */
/*{{{ 6*/
check++;
pz=(*check)[dpl_Z];
if (pz<minz) minz=pz;
else if (pz>maxz) maxz=pz;
/*}}} */
/*{{{ 7*/
check++;
pz=(*check)[dpl_Z];
if (pz<minz) minz=pz;
else if (pz>maxz) maxz=pz;
/*}}} */
/*}}} */
/*{{{ behind me*/
if (maxz<hith) {
/* printf ("maxz < hither\n" ); */
return(triv_reject);
}
/*}}} */
/*{{{ beyond far clip*/
else if (minz>yo) {
/*
printf ("minz > yon (eye at %f,%f,%f\n",
v->f[3][0],
v->f[3][1],
v->f[3][2] );
*/
return(triv_reject);
}
/*}}} */
if (maxz>yo) code|=clip_yon;
if (minz<hith) code|=clip_hither;
}
/*{{{ check y0*/
posses=bbox_plane ( bound, v->plane_y0 );
if (posses==triv_posses) {
/* printf ("rejected on y0\n" ); */
return (triv_reject);
}
else if (posses != accept_posses) {
code|=clip_y0;
}
/*}}} */
/*{{{ y1*/
posses=bbox_plane ( bound, v->plane_y1 );
if (posses==triv_posses) {
/* printf ("rejected on y1\n" ); */
return (triv_reject);
}
else if (posses != accept_posses) {
code|=clip_y1;
}
/*}}} */
/*{{{ check x0*/
posses=bbox_plane ( bound, v->plane_x0 );
if (posses==triv_posses) {
/* printf ("rejected on x0\n" ); */
return (triv_reject);
}
else if (posses != accept_posses) {
code|=clip_x0;
}
/*}}} */
/*{{{ x1*/
posses=bbox_plane ( bound, v->plane_x1 );
if (posses==triv_posses) {
/* printf ("rejected on x1\n" ); */
return (triv_reject);
}
else if (posses != accept_posses) {
code|=clip_x1;
}
/*}}} */
return(code);
}
/*}}} */
#if 0
/*{{{ control calls*/
extern quick_renorm ( float *store, float x, float y, float z, float post_scale );
extern float quick_radius ( float, float, float );
int total_grab_patch=0,
total_grab_light=0;
static MATERIAL *f_mtl_override=NULL,
*b_mtl_override=NULL;
static TEXTURE *f_tex_override=NULL,
*b_tex_override=NULL;
static float sphere_scale;
static double static_render_strip [((MAX_VERTICES+1) * 56) / 8];
/*{{{ void PAZinit ( int device, int x_size, int y_size,*/
static int inited=0;
void PAZinit ( int device, int x_size, int y_size,
int device_A, int device_B, int device_C,
int magic_A, int magic_B, int magic_C, int processor_id )
{
/* mallocs store required for rendering */
/* plus performs any user-specific initialization */
if (inited == 0) { /* should check for processor_id == me */
inited=1;
output_device=device;
open_fn= (stream_open) &fopen;
gets_fn= (stream_gets) &fgets;
close_fn=(stream_close) &fclose;
render_strip=(VERTEX *) &static_render_strip[0];
/* printf ("render_strip at 0x%x\n", render_strip ); */
_LinkVertices(render_strip, MAX_VERTICES);
render_init( x_size, y_size );
}
}
/*}}} */
/*{{{ static void replace_strip ( VSTRIP *strip, int verts )*/
static void replace_strip ( VSTRIP *strip, int verts )
{
int i;
VERTEX *head,
*prev=NULL;
/*
printf ("replace_strip, vstrip 0x%x head 0x%x verts %d\n",
strip, strip->head, verts );
*/
if (strip->head)
free(strip->head);
strip->head=_NewVertices(verts);
if (strip->head) {
for (head=strip->head, i=0; i<verts; i++) {
if (prev)
prev->next=head;
prev=head;
head++;
}
prev->next=NULL;
}
else {
printf ( "Failed to allocate %d vertices, shared_cntl 0x%x\n",
verts, shared_cntl );
}
}
/*}}} */
/*{{{ on usage of patch / light render records*/
/*
These are run-time allocated records which flatten out the
heirarchical, multiply-instanced datastructures in PAZ to be
individual patches, with clip-codes and materials.
There are 2 types of structure, CHUNKS and RECs. RECs are taken
out of CHUNKS until the CHUNK is exhausted, when a new CHUNK is allocated.
There is an ACTIVE chunk, the chunk from which allocation is currently
taking place. When the active chunk is exhausted, it has a USAGE and a
COUNT written into it. The usage is the number of bytes used up in the
chunk, the count is the number of patches / lights in this chunk. A
count of 0 indicates the last chunk in the list, or a NULL next field.
This allows a partial list to be used for rendering, so the length of the
allocated list is the high water mark.
*/
/*}}} */
/*{{{ static void render_inst ( INSTANCE *inst, VIEW *view, LIGHT *lights, MATRIX f, MATRIX b )*/
static void render_inst ( INSTANCE *root, LIGHTSOURCE *lights,
MATRIX f_parent, MATRIX b_parent, int nested )
{
INSTANCE *inst;
MATRIX front, back;
if (nested > 32) {
printf ("Are you sure there are 32 heirarchy levels here?\n" );
return;
}
for (inst=root; inst!=NULL;
inst=(INSTANCE *) nameToAddress((int)inst->link, viz_createInstance )) {
if (inst->enable & dirty_mtx) {
_invert ( inst->b, inst->f );
inst->enable^=dirty_mtx;
}
dpl_Concat ( front, inst->f, f_parent, 1 );
dpl_Concat ( back, inst->b, b_parent, 0 );
if (tree_enable(inst)) {
render_inst ( nameToAddress((int) inst->nest, viz_createInstance ),
lights, front, back, nested+1 );
}
if (inst_enable(inst)) {
/* hack, should be parameters */
if (inst->obj) {
f_mtl_override=(MATERIAL *) nameToAddress((int)inst->f_material,
viz_createMaterial );
b_mtl_override=(MATERIAL *) nameToAddress((int)inst->b_material,
viz_createMaterial );
f_tex_override=(TEXTURE *) nameToAddress((int)inst->f_texture,
viz_texture );
b_tex_override=(TEXTURE *) nameToAddress((int)inst->b_texture,
viz_texture );
if (inst->billboard) {
billboardize ( front, back );
}
_renderObj ( (OBJECT *) (nameToAddress((int) inst->obj, viz_createObject)),
front, back,
lights, vrthead,
&inst->lastLODindex,
0 );
}
}
}
}
/*}}} */
/*{{{ static int build_displaylist ( LIGHTSOURCE *non_ambient )*/
static int build_displaylist ( LIGHTSOURCE *non_ambient )
{
SCENE *s=currentScene;
INSTANCE *inst;
MATRIX f, b;
int then, now, insts=0;
dN_timer(&then);
for (inst=s->instances.head; inst!=NULL; inst=inst->next ) {
/*
this is a bit tacky due to heirarchies - only render if it's
a) enabled and b) root of a heirarchy
note that enable is now bit-packed
*/
if (inst->enable && (inst->daddy==NULL)) {
/* for recursive render to work */
PAZidMatrix(f);
PAZidMatrix(b);
render_inst ( inst, non_ambient, f, b, 1 );
insts++;
}
}
dN_timer(&now);
return (now-then);
}
/*}}} */
/*{{{ void PAZrenderScene ( int me, int nodes )*/
/*
PAZrenderScene for pxpl5
rendering is now peformed in 2 passes - an initial cull pass
is performed which contructs a displaylist of visible patches/pmeshes
this displaylist is then transformed into pxpl5 coefficients by the
pair of i860s chasing each other's tails.
multi-processor issues - it would be really cool to get one processor
to cull the left eye while the other culls the right eye. This should
halve the cull time of stereo on a single boardset.
*/
static int reordered=0;
extern MATERIAL *mdefault;
void PAZrenderScene ( int me, int nodes )
{
SCENE *s=currentScene;
POINT sect;
INSTANCE *inst, *sectinst=NULL;
MATERIAL *fm, *bm;
LIGHTSOURCE *non_ambient=reorderLights ( &s->lights.head );
int views_for_me;
checkNull(currentScene, "Attempt to render NULL scene\n");
/*{{{ re-allocate strips if they have grown*/
/* do some tracing and ultimately some rearranging */
if (shared_cntl->length_longest_strip > prev_longest_strip) {
prev_longest_strip=shared_cntl->length_longest_strip;
/*
if (_processorId==0)
printf ("longest strip got bigger, %d\n", prev_longest_strip );
*/
replace_strip ( &longest_strip, prev_longest_strip );
}
if (shared_cntl->length_longest_verts > prev_longest_verts) {
prev_longest_verts=shared_cntl->length_longest_verts;
/*
if (_processorId==0)
printf ("longest verts got bigger, %d\n", prev_longest_verts );
*/
replace_strip ( &longest_verts, prev_longest_verts );
}
if (shared_cntl->length_longest_tris > prev_longest_tris) {
prev_longest_tris=shared_cntl->length_longest_tris;
/*
if (_processorId==0)
printf ("longest tris got bigger, %d\n", prev_longest_tris );
*/
replace_strip ( &longest_tris, prev_longest_tris );
}
/*}}} */
views_for_me=vrtlist ( "renderScene") ;
if (reordered == 0) {
if (views_for_me == 1) {
reorderViews(s);
reordered=1;
}
}
if (_processorId == 0) {
resolve_scene (s);
XP_flush();
}
billboardstuff(s->eyes.head);
step_fx();
cull_pass_microsex=build_displaylist ( non_ambient );
render_displaylist ( 1 );
if (views_for_me==2) {
VIEWRT *pushvrt=vrthead;
/* swap vrt 0 and vrt 1 */
vrthead=pushvrt->next;
cull_pass_microsex+=build_displaylist ( non_ambient );
render_displaylist ( 0 );
vrthead=pushvrt;
}
flip_screens ( me, nodes );
}
/*}}} */
/*{{{ void PAZsetBackGND ()*/
float PAZback_r,
PAZback_g,
PAZback_b;
void PAZsetBackGND ( float r, float g, float b )
{
extern int eof_backR;
extern int eof_backG;
extern int eof_backB;
/*{{{ */
#if messages
printf ( "PAZsetBackgnd %f %f %f\n", r, g, b );
#endif
/*}}} */
PAZback_r = 255.9f * r;
PAZback_g = 255.9f * g;
PAZback_b = 255.9f * b;
if (output_device == i860_8_bit_device) {
back_colour = 256*r;
}
else if (output_device == i860_SV_device) {
unsigned int ir=255.9*r, ig=255.9*g, ib=255.9*b;
back_colour = (ib<<8) | (ig << 16) | (ir << 24);
}
else {
int ir=255.9*r, ig=255.9*g, ib=255.9*b;
ir = (ir | (ig << 8) | (ib << 16));
if (ir == 0) {
back_colour = 0xc0000000; /* -ve, yields 0 when negated and masked */
}
else
back_colour = -ir;
}
}
/*}}} */
/*}}} */
/*{{{ void xform_lights ( LIGHTSOURCE *bulb, MATRIX m )*/
void xform_lights ( cull_LMODEL *lm, dpl_MATRIX m )
{
register float *s, *d;
cull_LIGHT
cache_norm_matrix(m);
while (bulb) {
if (bulb->positional != light_ambient) {
s=(float *)bulb->position;
d=(float *)bulb->xformpos;
/* nxform_un_norm ( s, d); */
nxform ( s, d );
bulb=bulb->next;
}
}
}
/*}}} */
/*{{{ generate culled lmodel from lmodel*/
/*
phong stuff - malloc, compute and insert phong half-way
eye vector into each light bulb
*/
/*{{{ cook eye with back matrix*/
/*
for phong, we need to put eye in definition space also. this is
done by passing the view vector (0, 0, -1) thru concatenation of
forward viewing and backward modelling matrix, which is in
vrt->render_b
*/
invptr=(float *) render_b;
/* in view space, eye pointing in direction { 0, 0, -1 } */
/* pass this thru matrix ... */
/*
renormalize eye vector - the resulting H vector is scaled by
power_factor to save multiplies in the shading inner loop
*/
quick_renorm ( phongeye, -invptr[8], -invptr[9], -invptr[10], 1.0f );
/*}}} */
/*{{{ sod the phong - do the light thing*/
if (lights) {
/*{{{ how this maths works*/
/*
nasty vector maths frig - in the original phong model, we reflect the
view vector (from eye to surface) about the normal, and dot that with
the vector from the normal to the bulb.
In the H model, we compute the half-way vector between the eye and
the light bulb - this involves NEGATING the eye - here's why
eye ^ light
\ | /
\ | /
\ | /
\ | /
\|/
To maximize the highlight in model 1), the eye vector must point at the
surface, and the light vector must point AT the light. For the H model,
we must compute H to be the surface normal, which is light-eye.
the nasty frig is that the light is a POINT, so has a W coord, so
we cast the contents of the W coord into a float pointer, and drop
the H vector in there - jeez, that SUCKS
*/
/*}}} */
light_render_rec *light_rec, *light_head=NULL;
LIGHTSOURCE *bulb, *malloc_bulb=NULL, *prev_bulb=NULL;
for (bulb=lights; bulb; bulb=bulb->next ) {
POINT p;
if (keep_this_bulb ( bulb, centroid, p )) {
light_rec=new_light_rec();
if (light_head==NULL)
light_head=light_rec;
if (light_rec) {
malloc_bulb=&light_rec->light;
memcpy ( malloc_bulb, bulb, sizeof(LIGHTSOURCE));
malloc_bulb->colour[0]=p[3]*bulb->colour[0];
malloc_bulb->colour[1]=p[3]*bulb->colour[1];
malloc_bulb->colour[2]=p[3]*bulb->colour[2];
malloc_bulb->position[0]=p[0];
malloc_bulb->position[1]=p[1];
malloc_bulb->position[2]=p[2];
malloc_bulb->positional=light_directional;
malloc_bulb->next=NULL;
if (prev_bulb)
prev_bulb->next=malloc_bulb;
prev_bulb=malloc_bulb;
if (bulb->positional==light_directional) {
float **nasty=(float **) malloc_bulb->xformpos;
register float a, b, c;
nasty[3]=&(light_rec->Hvec[0]);
a=bulb->xformpos[0]-phongeye[0];
b=bulb->xformpos[1]-phongeye[1];
c=bulb->xformpos[2]-phongeye[2];
fix (a);
fix (b);
fix (c);
quick_renorm ( nasty[3], a, b, c, phong_precision * 0.99f );
}
}
else {
printf ( "Failed to allocate specular light bulb\n" );
}
}
}
if (light_head)
light_list=&light_head->light;
else
light_list=NULL;
}
/*}}} */
/*{{{ transform lights via back modelling matrix*/
if (light_list)
xform_lights ( light_list, invModel );
/*}}} */
/*}}} */
#endif
/*{{{ static void build_bound ( float32 bound[8][4], float32 minimax[2][4] )*/
static void build_bound ( float32 bound[8][4], float32 minimax[2][4] )
{
register float max_x, max_y, max_z, max_w;
register float min_x, min_y, min_z, min_w;
min_x=minimax[0][dpl_X];
min_y=minimax[0][dpl_Y];
min_z=minimax[0][dpl_Z];
min_w=1.0f;
max_x=minimax[1][dpl_X];
max_y=minimax[1][dpl_Y];
max_z=minimax[1][dpl_Z];
max_w=1.0f;
/*{{{ bound 0*/
bound[0][dpl_X]=min_x;
bound[0][dpl_Y]=min_y;
bound[0][dpl_Z]=min_z;
bound[0][dpl_W]=min_w;
/*}}} */
/*{{{ bound 1*/
bound[1][dpl_X]=max_x;
bound[1][dpl_Y]=min_y;
bound[1][dpl_Z]=min_z;
bound[1][dpl_W]=min_w;
/*}}} */
/*{{{ bound 2*/
bound[2][dpl_X]=min_x;
bound[2][dpl_Y]=max_y;
bound[2][dpl_Z]=min_z;
bound[2][dpl_W]=min_w;
/*}}} */
/*{{{ bound 3*/
bound[3][dpl_X]=max_x;
bound[3][dpl_Y]=max_y;
bound[3][dpl_Z]=min_z;
bound[3][dpl_W]=min_w;
/*}}} */
/*{{{ bound 4*/
bound[4][dpl_X]=min_x;
bound[4][dpl_Y]=min_y;
bound[4][dpl_Z]=max_z;
bound[4][dpl_W]=min_w;
/*}}} */
/*{{{ bound 5*/
bound[5][dpl_X]=max_x;
bound[5][dpl_Y]=min_y;
bound[5][dpl_Z]=max_z;
bound[5][dpl_W]=min_w;
/*}}} */
/*{{{ bound 6*/
bound[6][dpl_X]=min_x;
bound[6][dpl_Y]=max_y;
bound[6][dpl_Z]=max_z;
bound[6][dpl_W]=min_w;
/*}}} */
/*{{{ bound 7*/
bound[7][dpl_X]=max_x;
bound[7][dpl_Y]=max_y;
bound[7][dpl_Z]=max_z;
bound[7][dpl_W]=min_w;
/*}}} */
}
/*}}} */
/*{{{ next_free_ramp(dpl_RAMP *ramp)*/
static int
next_free_ramp(dpl_RAMP *ramp)
{
int i;
if (allocated_ramps == MAX_TEX_RAMPS) return 0;
for (i=0; i<allocated_ramps; i++ ) {
if (ref_texture_ramps[i] == ramp) return i;
}
ref_texture_ramps[allocated_ramps]=ramp;
setRampEntry ( &texture_ramps[allocated_ramps],
allocated_ramps,
ramp->color0[0],
ramp->color0[1],
ramp->color0[2],
ramp->color1[0],
ramp->color1[1],
ramp->color1[2] );
allocated_ramps++;
return allocated_ramps-1;
}
/*}}} */
/*{{{ static void cull_material ( cull_MATERIAL *cm,*/
static void cull_material ( cull_MATERIAL *cm,
dpl_MATERIAL *dm,
dpl_TEXTURE *t )
{
#define size_shift ((dvpx_texsize)-(dvpx_scalar))
#define id_shift ((dvpx_texid)-(dvpx_scalar))
#define ramp_shift ((dvpx_texrampsel)-(dvpx_scalar))
#define mode_shift ((dvpx_texmode)-(dvpx_scalar))
extern float* compute_phong_table ( float );
extern float animate_elapsed_time;
int ramp;
memcpy ( cm->diffuse,dm->diffuse, 3*sizeof(float));
cm->diffuse[3]=dm->opacity[0];
memcpy ( cm->specular,dm->specular, 3*sizeof(float));
cm->specular_table=compute_phong_table ( dm->specular[3] );
cm->pxpl5_cntl_word=-1; /* no texture == all ones */
if (t) {
dpl_TEXMAP *tm=t->texmap;
if (tm) {
if (dm->ramp)
ramp=next_free_ramp(dm->ramp);
else
ramp=0;
/*
2 bits of size
6 bits of id
2 bits of ramp
3 bits of mode
*/
cm->pxpl5_cntl_word = (tm->hwareSize << size_shift) |
(((tm->hwareOffs) & 63) << id_shift) |
(ramp << ramp_shift) |
(((t->minify-1) & 0x7) << mode_shift);
/*
printf ("cull material 0x%x to cntlword 0x%x bilinear %d\n",
dm,
cm->pxpl5_cntl_word,
t->minify==0x6 );
*/
cm->du=t->u0 + (t->du * animate_elapsed_time);
cm->dv=t->v0 + (t->dv * animate_elapsed_time);
cm->du=cm->du-(int) cm->du;
cm->dv=cm->dv-(int) cm->dv;
if (cm->du<0) cm->du+=1.0f;
if (cm->dv<0) cm->dv+=1.0f;
cm->du*=0.125f;
cm->dv*=0.125f;
}
}
}
/*}}} */
/*{{{ static LOD *whichLOD ( OBJECT *obj,*/
static dpl_LOD *whichLOD ( dpl_OBJECT *obj,
int *lastLODindex,
dpl_MATRIX full_matrix )
{
#if 0
/*{{{ real code which once worked*/
/*
given an object containing a list of LODs, a bounding box and
a forward matrix, this determines the correct LOD to draw
LODs are described as a pair of ranges, within which the LOD is
valid. For consistency it is necessary to remember between frames
which LOD we are in (since ranges must overlap for hysteresis).
LODs are sorted in ascending order, so the head of the LOD list has
the smallest value
*/
float LODscale;
float centrex,
centrey,
centrez;
int hunt, LODindex,
index=*lastLODindex;
LOD *lod, *prev=NULL;
if (obj == NULL) return NULL;
/*{{{ compute LODscale*/
/*
compute LODscale
pass centroid of obj->head thru matrix - centroid is half-way between
vertex 7 and vertex 0 of bound - note that centroid is held in bound[8]
*/
{
register float px, py, pz;
px=0.5f * (obj->bound[7][0]+obj->bound[0][0]);
py=0.5f * (obj->bound[7][1]+obj->bound[0][1]);
pz=0.5f * (obj->bound[7][2]+obj->bound[0][2]);
centrex=(px * model_matrix[0][0]) +
(py * model_matrix[1][0]) +
(pz * model_matrix[2][0]) +
model_matrix[3][0];
centrey=(px * model_matrix[0][1]) +
(py * model_matrix[1][1]) +
(pz * model_matrix[2][1]) +
model_matrix[3][1];
centrez=(px * model_matrix[0][2]) +
(py * model_matrix[1][2]) +
(pz * model_matrix[2][2]) +
model_matrix[3][2];
}
LODscale=quick_radius(centrex-view_matrix[3][0],
centrey-view_matrix[3][1],
centrez-view_matrix[3][2] );
/* printf ( "LODscale of %f for object 0x%x\n", LODscale, obj ); */
/*}}} */
/*{{{ move to previous LOD*/
lod=obj->head;
LODindex=0;
hunt=1;
while (hunt) {
if (LODindex == index)
hunt=0;
else {
LODindex++;
lod=lod->next;
if (lod==NULL) {
hunt= 0;
lod = obj->tail;
LODindex--;
}
}
}
/*}}} */
/*{{{ select lod for this frame*/
/*
printf ( "first guess at LOD %d, switch_in %f switch_out %f\n",
LODindex, lod->switch_in, lod->switch_out );
*/
if (LODscale < lod->switch_in) {
while (LODscale < lod->switch_in) {
if (lod->prev==NULL) break;
else {
LODindex--;
lod=lod->prev;
/* printf ("whichLOD moving to previous rep of 0x%x\n", obj ); */
}
}
}
else if (LODscale > lod->switch_out) {
while (LODscale > lod->switch_out) {
if (lod->next==NULL) return NULL;
else {
LODindex++;
lod=lod->next;
/* printf ("whichLOD moving to next rep of 0x%x\n", obj ); */
}
}
}
/*}}} */
/*{{{ patch data back into instance*/
*lastLODindex = LODindex;
/*}}} */
/*}}} */
#endif
dpl_list *l=obj->lod_list.head;
if (l)
return (dpl_LOD *) l->item;
else
return NULL;
}
/*}}} */
/*{{{ static void cull_lmodel ( dpl_LMODEL *lm, dpl_POINT centroid )*/
static void cull_lmodel ( dpl_LMODEL *lm, dpl_POINT centroid )
{
cull_LMODEL *lmp;
if (lm == NULL) {
printf ("cull_lmodel returning due to NULL lmodel\n" );
return;
}
lmp=new_draw_item ( lmodel_bump_val, dpl_type_lmodel );
if (lmp) {
lmp->evaluated = 0;
lmp->n_lights = 0;
lmp->lmodel =lm;
lmp->ambience[0]= 0;
lmp->ambience[1]= 0;
lmp->ambience[2]= 0;
memcpy ( lmp->centroid, centroid, 4*sizeof(float));
}
else {
printf ("Failed to allocate draw item\n" );
}
}
/*}}} */
/*{{{ static void cull_geogroup ( dpl_GEOGROUP *gg,*/
static void cull_geogroup ( dpl_GEOGROUP *gg,
dpl_MATRIX f,
dpl_MATRIX b,
dpl_POINT xform_eye,
cull_VIEW *eye,
int clip_code )
{
cull_GEOGROUP *prr;
dpl_MATERIAL *fm, *bm;
dpl_TEXTURE *ft, *bt;
int draw_mode=0;
if (f_mtl_override)
fm=f_mtl_override;
else
fm=gg->f_material;
if (b_mtl_override)
bm=b_mtl_override;
else
bm=gg->b_material;
if (fm) {
draw_mode =dpl_draw_front;
if (f_tex_override)
ft=f_tex_override;
else
ft=fm->texture;
}
if (bm) {
draw_mode|=dpl_draw_back;
if (b_tex_override)
bt=b_tex_override;
else
bt=bm->texture;
}
if (draw_mode) {
prr=new_draw_item(ggroup_bump_val, dpl_type_geogroup );
if (prr) {
if (fm)
cull_material ( &prr->front_mtl_data, fm, ft );
if (bm)
cull_material ( &prr->back_mtl_data, bm, bt );
prr->sphere_scale=sphere_scale;
prr->geo=gg;
prr->draw_mode = draw_mode|gg->draw_mode;
prr->frame_number = current_frame_count;
matrix_copy ( prr->forward, f );
matrix_copy ( prr->invModel, b );
memcpy ( prr->xform_eye, xform_eye, 3*sizeof(float));
prr->back_xf_eye[0]= -prr->xform_eye[0];
prr->back_xf_eye[1]= -prr->xform_eye[1];
prr->back_xf_eye[2]= -prr->xform_eye[2];
prr->xform_eye[3] = 1.0f;
prr->back_xf_eye[3]=-1.0f;
prr->clip_code = clip_code;
}
else {
printf ("Failed to allocate draw item\n" );
}
}
/*
*/
else {
printf ("Not bothering to draw, no materials\n" );
}
}
/*}}} */
/*{{{ static void cull_object ( dpl_OBJECT *obj,*/
static void cull_object ( dpl_OBJECT *obj,
dpl_MATRIX model,
dpl_LMODEL *lmodel,
cull_VIEW *eye,
int *LODindex )
{
/*{{{ local variables*/
/* this for fixing Phong (Blinn) half-eye vector */
#define fix(v) if (((v) > (-0.001)) && ((v) < 0.001)) (v)=0.001
static dpl_MATRIX render_f,
render_b;
dpl_MATRIX invModel;
dpl_POINT centroid;
dpl_POINT xformBound[8],
*pt=&xformBound[0];
dpl_LOD *lod;
dpl_list *gg_list;
int clip_code;
/*}}} */
/*{{{ concat view / model matrices*/
dpl_IdMatrix ( render_f );
/* this upside-downs the image, AND inverts the z-coord */
render_f [dpl_Z][dpl_Z]=-1;
render_f [dpl_Y][dpl_Y]=-1;
fn_concatenate ( render_f, eye->b, render_f );
fn_concatenate ( render_f, model, render_f );
sphere_scale = scale_from_matrix ( render_f );
dpl_Scale ( render_f, 1, eye->aspect_ratio, 1 );
/*}}} */
/*{{{ set up level-of-detail, bbox and clip code*/
/* NB ALWAYS compute lod for inter-eye consistency under clipping */
lod=whichLOD ( obj, LODindex, render_f );
if (lod==NULL) {
return;
}
build_bound ( xformBound, lod->bounds );
fn_xform_bound ( xformBound, xformBound, render_f );
clip_code=visibility(xformBound, eye);
/*}}} */
if (clip_code != triv_reject) {
int gcc;
/*{{{ now finally commit to inverting model matrix*/
dpl_Invert ( invModel, model );
fn_concatenate ( render_b, eye->f, invModel);
{
/* dpl_Scale ( render_b, 1, eye->aspect_ratio, 1, 0 ); */
dpl_MATRIX t;
dpl_IdMatrix (t);
t[dpl_Y][dpl_Y] = eye->aspect_ratio;
dpl_Concat ( render_b, t, render_b );
}
/*}}} */
/*{{{ compute xformed centroid of bbox*/
centroid[0]=0.5f * (lod->bounds[0][0] + lod->bounds[1][0]);
centroid[1]=0.5f * (lod->bounds[0][1] + lod->bounds[1][1]);
centroid[2]=0.5f * (lod->bounds[0][2] + lod->bounds[1][2]);
centroid[3]=1.0f;
dpl_XformPoint ( centroid, centroid, model );
/*}}} */
cull_lmodel ( lmodel, centroid );
for (gg_list=lod->geogroup_list.head; gg_list; gg_list=gg_list->next ) {
dpl_GEOGROUP *gg=(dpl_GEOGROUP *) gg_list->item;
/* printf ("clip_code 0x%x\n", clip_code ); */
if (clip_code == 0)
cull_geogroup ( gg, render_f, invModel, render_b[3], eye, 0 );
else if (clip_code != triv_reject) {
build_bound ( xformBound, gg->bounds );
fn_xform_bound ( xformBound, xformBound, render_f );
if ((gcc=visibility(xformBound, eye)) != triv_reject)
cull_geogroup ( gg, render_f, invModel, render_b[3], eye, gcc );
}
}
}
}
/*}}} */
/*{{{ static void cull_node ( dpl_MATRIX apply,*/
static void cull_node ( dpl_MATRIX apply,
dpl_DCS *node,
cull_VIEW *view,
dpl_LMODEL *lm )
{
/* node contains either a dpl_LIGHT*, or a dpl_INSTANCE* */
dpl_node *n=node->node;
if (n == NULL) {
return;
}
if (n->type_check == dpl_type_light) {
/*{{{ eval location / orientation of light*/
/* compute position - pass 0, 0, -1 down matrix */
dpl_LIGHT *l=(dpl_LIGHT *) n;
if (l->light_type == dpl_light_type_directional) {
l->position[0]=-apply[2][0];
l->position[1]=-apply[2][1];
l->position[2]=-apply[2][2];
}
else {
l->position[0]=-apply[3][0];
l->position[1]=-apply[3][1];
l->position[2]=-apply[3][2];
}
/*
printf ("culled light to %f,%f,%f\n",
l->position[0],
l->position[1],
l->position[2] );
*/
/*}}} */
}
else if (n->type_check == dpl_type_instance) {
/*{{{ cull this instance*/
dpl_INSTANCE *inst=(dpl_INSTANCE *) n;
dpl_MATRIX back;
if (lm == NULL) {
printf ("No lighting model, returning\n" );
return;
}
if (inst->object) {
/* if (inst->frame_count != current_frame_count) { */
inst->frame_count = current_frame_count;
f_mtl_override=inst->f_material;
b_mtl_override=inst->b_material;
f_tex_override=inst->f_texture;
b_tex_override=inst->b_texture;
if (inst->billboard)
billboardize ( apply, NULL );
/* printf ("cull object 0x%x\n", inst->object ); */
cull_object ( inst->object,
apply,
lm, view,
&inst->last_LOD_index );
}
/*}}} */
}
else {
printf ("Unexpected node type in dcs\n" );
}
}
/*}}} */
/*{{{ static void cull_tree ( dpl_MATRIX inherit,*/
static void cull_tree ( dpl_MATRIX inherit,
dpl_DCS *node,
cull_VIEW *v,
dpl_LMODEL *lm )
{
dpl_MATRIX m;
fn_concatenate ( m, node->matrix, inherit );
/* recurse down children */
if (node->child && (node->enable & dcs_subtree_enable))
cull_tree ( m, node->child, v, lm );
/* do myself */
if (node->enable & dcs_node_enable)
cull_node ( m, node, v, lm );
/* do my siblings */
while (node->sibling) {
node=node->sibling;
if (node->enable & dcs_node_enable) {
fn_concatenate ( m, node->matrix, inherit );
cull_node ( m, node, v, lm );
}
}
}
/*}}} */
/*{{{ cull_VIEW *veloci_cull ( dpl_VIEW *dv, POINT LOD_origin )*/
cull_VIEW *veloci_cull ( dpl_VIEW *dv, dpl_POINT LOD_origin )
{
extern dpl_SCENE the_scene;
static cull_VIEW view;
dpl_MATRIX id;
cull_VIEW *v=&view;
dpl_list *list;
dpl_ZONE *z;
int i;
/*{{{ do some inits*/
if (current_frame_count == 0) {
chunk_head=chunk_active=(ggroup_render_chunk *) malloc(sizeof(ggroup_render_chunk));
chunk_head->next=NULL;
chunk_head->ggroup_count=0;
chunk_head->usage=0;
chunk_head->terminal=1;
chunk_free_ptr=&chunk_head->ggroup_data[0];
}
else {
chunk_head->ggroup_count=0;
chunk_head->usage=0;
chunk_head->terminal=1;
chunk_free_ptr=&chunk_head->ggroup_data[0];
chunk_usage=0;
chunk_active=chunk_head;
}
/*}}} */
allocated_ramps=1; /* ALWAYS have ramp0 = 0.0 ==> 1.0 */
dpl_IdMatrix ( id );
current_frame_count++;
/* first make a cull_VIEW from dpl_VIEW */
cull_view ( v, dv );
for (list=dv->zone_list.head; list; list=list->next ) {
z=(dpl_ZONE *) list->item;
if (z->enable)
if (z->root)
cull_tree ( id, z->root, v, z->lmodel);
}
for (list=the_scene.zone_list.head; list; list=list->next ) {
z=(dpl_ZONE *) list->item;
if (z->enable)
if (z->root)
cull_tree ( id, z->root, v, z->lmodel);
}
v->geogroup_head=chunk_head;
return v;
}
/*}}} */