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>
1541 lines
39 KiB
C++
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;
|
|
}
|
|
/*}}} */
|
|
|