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

2408 lines
67 KiB
C++

/*{{{ banner*/
/* **************************************************
Copyright DIVISION Limited (c) 1994
All rights reserved
File : vr_draw.c
Project : dpl interface / velocirender
Author : PJA
Date : 14/07/94
Function: Implements the draw pass of v-render
The current scene has been culled, into a
drawable displaylist. The only items in this display
list are cull_GEOGROUPs and cull_LMODELS.
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 "vr_cull.h"
#include "texture.h"
#include "multicpu.h"
#include "speclght.h"
#include "pxpl5sup\divpxmap.h"
#include "pxpl5sup\pxpl5sup.h"
#include "pxpl5sup\pxpl5tri.h"
#include "pxpl5sup\dmaengn.h"
#include "\projects\dbi0150\dbi0151\ucode\igc_opco.h"
#include "\projects\dbi0150\dbi0151\ucode\igc_comm.h"
/*{{{ some globals here*/
int back_colour=0;
extern dpl_SCENE the_scene;
extern int current_frame_count;
/*}}} */
/*{{{ texture scrolling support*/
extern float Cdelta_u, Cdelta_v;
/*}}} */
/*{{{ specular lighting*/
float *vr_phong_table;
/*{{{ float *compute_phong_table ( float power )*/
float *compute_phong_table ( float power )
{
int ipower=(int) power;
float *t;
if (ipower < 2)
return &vr_phong_table[0];
ipower--;
if (ipower > max_power)
ipower=max_power-1;
ipower<<=phong_precision_shift;
t=&(vr_phong_table[ipower]);
/* printf ("compute_phong_table returning 0x%x %f %f %f %f\n", t, t[20], t[40], t[60], t[80] ); */
return t;
}
/*}}} */
/*{{{ void init_phong ( void )*/
void init_phong ( void )
{
/*
this mallocs and intializes an array of max_power tables,
each table phong_precision long
this is indexed by a.b to return exp(a,b)
table initialized by first setting table[i] to i,
then for each pass setting table[i] to i*prev_table[i]
*/
float *p;
int i, j;
vr_phong_table = (float *) malloc ( sizeof(float) * max_power * phong_precision );
for (j=0; j<phong_precision; j++ ) {
vr_phong_table[j] = ((float) (j+1)) / (float) phong_precision;
}
p=vr_phong_table;
for (i=1; i<max_power; i++) {
for (j=0; j<phong_precision; j++ ) {
float prev=*p;
float this=vr_phong_table[j];
p[phong_precision] = prev * this;
p++;
}
}
}
/*}}} */
/*}}} */
/*{{{ some very pxpl5-specific stuff*/
/*{{{ a pile of statics and not-so-statics*/
#define MAX_RAMPS 4
extern concurrency_control *shared_cntl;
extern int* tile_poke_address;
extern int* wait_poke_address;
extern int* trans_wait_poke_address;
extern int *texture_table_iptr;
extern int _processorId,
_numProcessors;
static int display_tile_base=0;
static int timing_frames=0;
static int rendered_frames=0;
static int very_first_frame=0;
static int x_display_tiles, y_display_tiles;
static int first_framebuf_y = 0,
framebuf_flip = 4,
second_screen_flip=16;
static screenbin *prevBin=NULL;
static int prevX,
prevY;
static int unclipped_tris = 0;
static int farz_drawn_tris = 0;
static int farz_rejected_tris = 0;
static int clipped_tris = 0;
static int clipped_patches = 0;
static int unclipped_patches = 0;
/*}}} */
/*{{{ void multisync()*/
int multisyncs=0;
void multisync(void) /* char * str ) */
{
/*{{{ multisync algorithm*/
/*
this function interlocks all processors on a shared memory board,
and must leave the shared_cntl region in the same state as when
it entered
algorithm - a single lock determines how many processors are
currently spinning. The processor which increments the lock up
to numProcessors clears the lock and triggers all other processors
to go -
semwait();
shared->lock++;
if (shared->lock==num_processors) {
shared->lock=0;
for (i=0; i<num_processors; i++) {
go[i]=0;
}
semsignal();
}
else {
go[i]=1;
semsignal();
while (go[i])
bla();
}
}
*/
/*}}} */
concurrency_control *shared=shared_cntl;
Semaphore *sem=&shared->sem;
int i, t,
me =_processorId,
them=_numProcessors,
*spin=&shared->go[me];
return;
multisyncs++;
/*
printf ("(%d) multisync %d : %s\n",
_processorId, multisyncs, str );
*/
SemWait ( sem, me );
t=++shared->locker;
if (t==them) {
shared->locker=0;
shared->go[0]=0;
shared->go[1]=0;
shared->go[2]=0;
shared->go[3]=0;
}
else
*spin=1;
/* quick signal */
sem->lock[me]=0;
while (*spin)
bla(100); /* hit uncached ram every 3 uS */
}
/*}}} */
/*{{{ static void start_frame_stats ( void )*/
static void start_frame_stats ( void )
{
unclipped_tris = 0;
farz_drawn_tris = 0;
farz_rejected_tris = 0;
clipped_tris = 0;
clipped_patches = 0;
unclipped_patches = 0;
}
/*}}} */
/*{{{ static void add_DMA_opcodes ( screenbin *bin, int *opcodes, int n_opcodes )*/
static void add_DMA_opcodes ( screenbin *bin, int *opcodes, int n_opcodes )
{
binchunk *chunk=bin->tail;
int usage=chunk->usage;
int index=usage>>2;
/* usage in bytes */
if ((BIN_FULL - usage) < (n_opcodes << 2)) {
/*{{{ grab a new one*/
chunk->next=next_binchunk ();
chunk->DMA_opcodes[index ]=(int) (&chunk->next->DMA_opcodes[0]);
chunk->DMA_opcodes[index+1]=DMA_GOTO_VAL;
chunk->usage=BIN_FULL;
chunk=chunk->next;
chunk->next=NULL;
bin->tail=chunk;
usage=0;
index=0;
/*}}} */
}
memcpy ( &chunk->DMA_opcodes[index], opcodes, n_opcodes<<2 );
chunk->usage+=n_opcodes<<2;
}
/*}}} */
/*{{{ void setpxpl5VideoMode ( int magicVal )*/
void setpxpl5VideoMode ( int mode )
{
if (mode & 4) {
first_framebuf_y= 16;
framebuf_flip = 4;
}
else if (mode & 16) {
framebuf_flip = 4;
}
else if (mode & 8) {
/* hi-res 1024x1024 */
first_framebuf_y = 0;
framebuf_flip = 8;
}
else {
first_framebuf_y = 0;
framebuf_flip = 4;
}
if (mode & 128)
first_framebuf_y= 16;
}
/*}}} */
static int *DMA_copy,
*transp_DMA_copy;
int recompute_end_of_frame=1;
/*{{{ static screenbin *strap_up_transptiles ( int x_display_tiles,*/
static screenbin *strap_up_transptiles ( int x_display_tiles,
int y_display_tiles,
screenbin *screenbins,
screenbin *trans_screenbins,
int first_framebuf_y,
int strap_last )
{
/* ************************************************
This is a bit tricky, since we are dealing with the PREVIOUS opaque
tile and the CURRENT transparent tile. We are holding a pointer to
the previous opaque bin, a pointer to the current opaque bin, and
a pointer to the current transparent bin. If there is any transparent
stuff, we patch the PREV opaque to point to the current transp. Then
patch the current transp to point to the current opaque. If no transp
stuff, we patch the previous opaque to the current opaque. At the end,
we just patch the previous opaque bin to NULL.
************************************* */
int x, y,
px=prevX,
py=prevY;
screenbin *prevbin=prevBin;
screenbin *headbin=NULL;
int *DMA_seq = shared_cntl->eof_DMA_sequence;
int *transp_DMA_seq = shared_cntl->transp_eof_DMA_sequence;
int *eot_DMA_seq = shared_cntl->eot_DMA_sequence;
int *transp_eot_DMA_seq = shared_cntl->transp_eot_DMA_sequence;
int eofwords = shared_cntl->eof_DMA_words;
int transp_eofwords = shared_cntl->transp_eof_DMA_words;
for (x=0; x<x_display_tiles; x++ ) {
for (y=0; y<y_display_tiles; y++ ) {
screenbin *thisbin =&screenbins [x+(y*(1024/64))];
screenbin *transbin=&trans_screenbins[x+(y*(1024/64))];
float *hack =(float *) &thisbin->head->DMA_opcodes[0];
float *trans_hack=(float *) &transbin->head->DMA_opcodes[0];
if (transbin->head->usage!=transbin->head->DMA_opcodes[63]) {
/*{{{ transparent branch*/
/* copy end-of-frame DMA opcodes into opaque bin */
if (prevbin != NULL) {
*tile_poke_address =px | ((py+display_tile_base) << 5);
*wait_poke_address =DMA_WAIT_VAL;
/* prev opaque GOTO this transp */
DMA_seq[eofwords ]=(int) &transbin->head->DMA_opcodes[2];
DMA_seq[eofwords+1]=DMA_GOTO_VAL;
/* this transp GOTO this opaque */
transp_DMA_seq[transp_eofwords ]=(int) &thisbin->head->DMA_opcodes[2];
transp_DMA_seq[transp_eofwords+1]=DMA_GOTO_VAL;
add_DMA_opcodes ( prevbin, DMA_seq, eofwords+2 );
add_DMA_opcodes ( transbin, transp_DMA_seq, transp_eofwords+2 );
*trans_wait_poke_address=DMA_WAIT_VAL;
}
else {
/* must patch up the transp bin, as he is head of DMA execute op */
headbin=transbin;
transbin->head->DMA_opcodes[0]=0;
transbin->head->DMA_opcodes[1]=0;
/* this transp GOTO this opaque */
transp_DMA_seq[transp_eofwords ]=(int) &thisbin->head->DMA_opcodes[2];
transp_DMA_seq[transp_eofwords+1]=DMA_GOTO_VAL;
add_DMA_opcodes ( transbin, transp_DMA_seq, transp_eofwords+2 );
*trans_wait_poke_address=DMA_WAIT_VAL;
}
/*}}} */
}
else {
/*{{{ opaque*/
if (prevbin != NULL) {
*tile_poke_address=px | ((py+display_tile_base) << 5);
DMA_seq[eofwords ]=(int) &thisbin->head->DMA_opcodes[2];
DMA_seq[eofwords+1]=DMA_GOTO_VAL;
add_DMA_opcodes ( prevbin, DMA_seq, eofwords+2 );
*wait_poke_address=DMA_WAIT_VAL;
}
else {
headbin=thisbin;
thisbin->head->DMA_opcodes[0]=0;
thisbin->head->DMA_opcodes[1]=0;
}
/*}}} */
}
py=y+first_framebuf_y;
px=x;
prevbin=thisbin;
}
}
if (strap_last) {
*tile_poke_address=px | ((py+display_tile_base) << 5);
DMA_seq[eofwords ]=0;
DMA_seq[eofwords+1]=DMA_STOP_VAL | 0x08000000;
add_DMA_opcodes ( prevbin, DMA_seq, eofwords+2 );
}
else
prevBin =prevbin;
prevX=px;
prevY=py;
return headbin;
}
/*}}} */
/*{{{ static void redo_end_of_frame()*/
extern int eof_FOG_rval,
eof_FOG_gval,
eof_FOG_bval,
eof_backR,
eof_backG,
eof_backB,
eof_Z_near,
eof_Z_far,
eof_farZ;
static void redo_end_of_frame ( void )
{
shared_cntl->eof_DMA_words = short_end_of_frame_DMA ( shared_cntl->eof_DMA_sequence,
shared_cntl->eof_sequence,
shared_cntl->eot_DMA_sequence );
shared_cntl->eot_DMA_words = end_of_textr_DMA ( shared_cntl->eot_DMA_sequence,
shared_cntl->eot_sequence );
recompute_end_of_frame=0;
}
/*}}} */
/*{{{ static void pxpl5_flip ( int me, int nodes )*/
static void pxpl5_flip ( int me, int nodes )
{
/*{{{ what we do*/
/* *********************************
We need to construct a linked list of tiles.
For all tiles the first DMA instruction is a GOT0 (next tile). For the
last tile, the destination is NULL. These instructions are
never executed, but they are used by the driver to re-trigger
the DMA engine per tile.
*/
/*}}} */
/*{{{ declare variables*/
extern int dN_pxpl5_dma ( int *address, int *ack_address, int *txdn_address,
vfptr pre_dma );
extern int replying;
extern cull_RAMP texture_ramps[MAX_RAMPS];
screenbin *headbin;
int stereo=0;
int spintime, words;
int i;
int pthen, pnow, pmicrosex;
/*}}} */
prevBin=NULL;
/*{{{ patch in texture ramps*/
if (texture_table_iptr) {
for (i=0; i<MAX_RAMPS; i++ ) {
texture_table_iptr[(i*3)+2]=texture_ramps[i].codeWord;
}
}
/*}}} */
/*{{{ strap up tiles*/
/*
this now does NO interrupting of tranny, except for very last tile
this needs tidying, all these fn calls will cost around 1mS!!
*/
headbin=strap_up_transptiles ( x_display_tiles, y_display_tiles,
screenbins, trans_screenbins,
first_framebuf_y,
1 );
/* needs to deal with stereo on a single pipe, such as ... */
/* first_framebuf_y^=second_screen_flip; */
/*}}} */
/*{{{ RENDER THIS FRAME ! ! ! ! do DMA rendering*/
/* spin on an uncached location */
if (_processorId==0) {
/* flush(); */
vfptr eof;
if (recompute_end_of_frame)
eof=&redo_end_of_frame;
else
eof=NULL;
spintime=dN_pxpl5_dma ((int *)(headbin->head),
shared_cntl->uncache_debug_block,
shared_cntl->eot_DMA_sequence,
eof );
if (spintime > 500000)
printf ("is this right - spintime=%d\n", spintime );
recompute_end_of_frame=0;
multisync();
}
else {
multisync();
}
/*}}} */
start_frame_stats();
/*{{{ flip all buffer space*/
if (screenbins == screen0bins) {
screenbins =screen1bins;
trans_screenbins =trans_screen1bins;
}
else if (screenbins == screen1bins) {
screenbins =screen0bins;
trans_screenbins =trans_screen0bins;
}
else {
printf ("WHOAH - screenbins neither screen0 nor screen1 0x%x 0x%x 0x%x\n",
screenbins, screen0bins, screen1bins );
while (1)
;
}
liberate_screenbins ( screenbins, 1024, 768 );
liberate_screenbins ( trans_screenbins, 1024, 768 );
if (lastcoeffptr == (float *) coeffstore0) {
coefficient_ptr = (float *) coeffstore1;
last_coeffchunk = coeffstore1;
}
else {
coefficient_ptr = (float *) coeffstore0;
last_coeffchunk = coeffstore0;
}
lastcoeffptr=coefficient_ptr;
/*}}} */
/*{{{ housekeeping*/
display_tile_base^=framebuf_flip;
/*}}} */
}
/*}}} */
/*{{{ void flip_screens( int me, int nodes )*/
void flip_screens( int me, int nodes )
{
int xd, yd, back_c;
if (very_first_frame==0) {
int i, j, tile=0;
int *cptr=shared_cntl->eof_sequence,
*cptr0=cptr;
for (i=0; i<64; i++ )
cptr[i]=0x0;
IGC_SETENABS ( cptr );
IGC_CLEAR ( cptr, 0, 32 );
IGC_BSWAIT ( cptr );
IGC_NOOP ( cptr );
IGC_NOOP ( cptr );
IGC_NOOP ( cptr );
IGC_VRAMWrite ( cptr, 4 );
IGC_NOOP ( cptr );
IGC_NOOP ( cptr );
IGC_NOOP ( cptr );
IGC_NOOP ( cptr );
for ( i=0; i<32; i++ ) {
/*{{{ */
int *ptr =shared_cntl->eof_DMA_sequence,
*ptr0=ptr;
*ptr++=0x0;
*ptr++=0x0;
for (j=0; j<32; j++ ) {
*ptr++=tile;
*ptr++=DMA_TILE_VAL;
*ptr++=(int32) cptr;
*ptr++=DMA_FLUSH_VAL;
*ptr++=(int32) cptr;
*ptr++=DMA_FLUSH_VAL;
*ptr++=(int32) cptr0;
*ptr++=DMA_SEND_VAL | 16;
*ptr++=(int32) cptr;
*ptr++=DMA_FLUSH_VAL;
*ptr++=0;
*ptr++=DMA_FLUSH_VAL;
tile++;
}
*ptr++=0;
*ptr++=DMA_STOP_VAL | 0x08000000;
/*}}} */
dN_pxpl5_dma (ptr0,
shared_cntl->uncache_debug_block,
shared_cntl->eot_DMA_sequence,
NULL );
}
very_first_frame++;
shared_cntl->eof_DMA_words = short_end_of_frame_DMA ( shared_cntl->eof_DMA_sequence,
shared_cntl->eof_sequence,
shared_cntl->eot_DMA_sequence );
}
pxpl5_flip ( me, nodes );
return;
if (very_first_frame < 2) {
back_c=back_colour;
back_colour=0;
yd=y_display_tiles;
xd=x_display_tiles;
x_display_tiles= 1024/64;
y_display_tiles= 768/128;
}
pxpl5_flip ( me, nodes );
if (very_first_frame<2) {
back_colour=back_c;
y_display_tiles=yd;
x_display_tiles=xd;
very_first_frame++;
}
}
/*}}} */
/*{{{ void render_init()*/
/* this is a job for cull, in my book */
extern int getFsr ( void );
extern void setFsr ( int fsr );
static int render_inited=0;
void render_init( int x_size, int y_size )
{
int i, j;
int *p;
float then, now;
int *time_end_of_frame;
multisync();
if (render_inited == 0) {
int fsr;
render_inited=1;
setRampEntry ( &texture_ramps[0], 0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0 );
setRampEntry ( &texture_ramps[1], 1, 0.3, 0.0, 0.0, 1.0, 1.0, 0.9 );
setRampEntry ( &texture_ramps[2], 2, 0.0, 0.5, 0.0, 1.0, 1.0, 1.0 );
setRampEntry ( &texture_ramps[3], 3, 0.0, 0.0, 0.4, 0.9, 0.9, 1.0 );
texInit ();
setFsr(1|getFsr());
x_display_tiles=(x_size + 63) >> 6;
y_display_tiles=(y_size + 127) >> 7;
display_tile_base=0;
/*
printf ( "x_tiles = %d y_tiles = %d\n",
x_display_tiles,
y_display_tiles );
*/
init_phong ();
if (_processorId==0) {
/* printf ("render_init shared_cntl at 0x%x\n", shared_cntl ); */
shared_cntl->uncache_debug_block = newBytes(4096*2);
shared_cntl->eof_DMA_sequence = newBytes(4096*2);
shared_cntl->eof_sequence = newBytes(4096*2);
DMA_copy=malloc(2048);
shared_cntl->transp_eof_DMA_sequence = newBytes(4096*2);
shared_cntl->transp_eof_sequence = newBytes(4096*2);
transp_DMA_copy=malloc(2048);
shared_cntl->eot_DMA_sequence = newBytes(4096*2);
shared_cntl->eot_sequence = newBytes(4096*2);
shared_cntl->transp_eot_DMA_sequence = newBytes(4096*2);
shared_cntl->transp_eot_sequence = newBytes(4096*2);
shared_cntl->uncached_flush_location = newBytes(4096*2);
/*
printf ("eof_DMA_sequence = 0x%x\n", shared_cntl->eof_DMA_sequence );
printf ("eof_sequence = 0x%x\n", shared_cntl->eof_sequence );
printf ("eot_DMA_sequence = 0x%x\n", shared_cntl->eot_DMA_sequence );
printf ("eot_sequence = 0x%x\n", shared_cntl->eot_sequence );
printf ("treof_DMA_sequence = 0x%x\n", shared_cntl->transp_eof_DMA_sequence );
printf ("treof_sequence = 0x%x\n", shared_cntl->transp_eof_sequence );
printf ("treot_DMA_sequence = 0x%x\n", shared_cntl->transp_eot_DMA_sequence );
printf ("treot_sequence = 0x%x\n", shared_cntl->transp_eot_sequence );
*/
/* we have 64k bytes to fit in end_of_frame and end_of_texture sequences */
shared_cntl->eot_DMA_words = end_of_textr_DMA ( shared_cntl->eot_DMA_sequence,
shared_cntl->eot_sequence );
shared_cntl->transp_eot_DMA_words = end_of_transp_DMA ( shared_cntl->transp_eot_DMA_sequence,
shared_cntl->transp_eot_sequence );
shared_cntl->eof_DMA_words = short_end_of_frame_DMA ( shared_cntl->eof_DMA_sequence,
shared_cntl->eof_sequence,
shared_cntl->eot_DMA_sequence,
45, 66, 135, 20 );
shared_cntl->transp_eof_DMA_words = end_of_transframe_DMA ( shared_cntl->transp_eof_DMA_sequence,
shared_cntl->transp_eof_sequence,
shared_cntl->transp_eot_DMA_sequence );
multisync();
}
else
multisync();
#if 0
/*{{{ time end of frame*/
/* attempt to time end-of-frame, end of texture */
time_end_of_frame=newBytes(128*4*(shared_cntl->eot_DMA_words+shared_cntl->eof_DMA_words));
{
int usecs, then, now, index=0, ix;
time_end_of_frame[index++]=0x0;
time_end_of_frame[index++]=0x0;
for (i=0; i<128;i++) {
for (ix=0; ix<shared_cntl->eof_DMA_words;ix++ ) {
time_end_of_frame[index++]=shared_cntl->eof_DMA_sequence[ix];
}
}
time_end_of_frame[index++]=0x0;
time_end_of_frame[index++]=0xf8000000;
dN_timer (&then);
for (i=0; i<128; i++ )
dN_pxpl5_dma ( time_end_of_frame, shared_cntl->uncache_debug_block, shared_cntl->eot_DMA_sequence );
dN_timer (&now);
usecs=now - then;
then=now;
printf ("%d uSecs for 16384 end-of-frames\n", usecs );
}
/*}}} */
/*{{{ time end of texture*/
/* attempt to time end-of-frame, end of texture */
time_end_of_frame=newBytes(128*4*(shared_cntl->eot_DMA_words+shared_cntl->eof_DMA_words));
{
int usecs, then, now, index=0, ix;
time_end_of_frame[index++]=0x0;
time_end_of_frame[index++]=0x0;
for (i=0; i<128;i++) {
for (ix=0; ix<shared_cntl->eot_DMA_words;ix++ ) {
time_end_of_frame[index++]=shared_cntl->eot_DMA_sequence[ix];
}
}
time_end_of_frame[index++]=0x0;
time_end_of_frame[index++]=0xf8000000;
dN_timer (&then);
for (i=0; i<128; i++ )
dN_pxpl5_dma ( time_end_of_frame, shared_cntl->uncache_debug_block, shared_cntl->eot_DMA_sequence );
dN_timer (&now);
usecs=now - then;
then=now;
printf ("%d uSecs for 16384 end-of-textures\n", usecs );
}
/*}}} */
/*{{{ time end of frame and texture*/
/* attempt to time end-of-frame, end of texture */
time_end_of_frame=newBytes(128*4*(shared_cntl->eot_DMA_words+shared_cntl->eof_DMA_words));
{
int usecs, then, now, index=0, ix;
time_end_of_frame[index++]=0x0;
time_end_of_frame[index++]=0x0;
for (i=0; i<128;i++) {
for (ix=0; ix<shared_cntl->eof_DMA_words;ix++ ) {
time_end_of_frame[index++]=shared_cntl->eof_DMA_sequence[ix];
}
for (ix=0; ix<shared_cntl->eot_DMA_words;ix++ ) {
time_end_of_frame[index++]=shared_cntl->eot_DMA_sequence[ix];
}
}
time_end_of_frame[index++]=0x0;
time_end_of_frame[index++]=0xf8000000;
dN_timer (&then);
for (i=0; i<128; i++ )
dN_pxpl5_dma ( time_end_of_frame, shared_cntl->uncache_debug_block, shared_cntl->eot_DMA_sequence );
dN_timer (&now);
usecs=now - then;
then=now;
printf ("%d uSecs for 16384 end-of-frame / textures\n", usecs );
}
/*}}} */
#endif
create_screenbins ( 1024, 768, x_size == 1024 );
{
extern float Cmax_y, Cmax_x;
Cmax_x=((float) x_size) - 0.01f;
Cmax_y=((float) y_size) - 0.01f;
}
/*
printf ("screen0bins =0x%x\n", screen0bins );
printf ("screen1bins =0x%x\n", screen1bins );
printf ("and screenbins=0x%x\n", screenbins );
*/
multisync();
}
}
/*}}} */
/*{{{ vpx_geometry_function vpx_drawstuff ( float *codeword,*/
vpx_geometry_function vpx_drawstuff ( float *codeword,
int *opcode0,
cull_GEOGROUP *cull_gg,
cull_MATERIAL *mtl )
{
*(int *) codeword=mtl->pxpl5_cntl_word;
*opcode0 = 31 - (int) (31.0f * mtl->diffuse[3]);
if (mtl->pxpl5_cntl_word != 0) {
if (cull_gg->draw_mode & (dpl_draw_smooth|dpl_draw_colored))
return (vpx_geometry_function) tri_zb_rgb_t;
else
return (vpx_geometry_function) tri_zb_f_t;
}
else {
if (cull_gg->draw_mode & (dpl_draw_smooth|dpl_draw_colored))
return (vpx_geometry_function) tri_zb_rgb;
else
return (vpx_geometry_function) tri_zb_f;
}
}
/*}}} */
/*}}} */
/*{{{ lighting geometries*/
/*{{{ eval_lmodel ( cull_LMODEL *lm, cull_GEOGROUP *gg )*/
static void
eval_lmodel ( cull_LMODEL *lm, cull_GEOGROUP *gg )
{
extern void printf_matrix ( dpl_MATRIX m );
extern void quick_renorm ( float *, float, float, float, float );
int i, dest_ix=0;
cull_LIGHT *dest_p=&lm->lights[0];
dpl_LMODEL *dlm=lm->lmodel;
dpl_list *l;
register float m00=gg->invModel[0][0];
register float m01=gg->invModel[0][1];
register float m02=gg->invModel[0][2];
register float m10=gg->invModel[1][0];
register float m11=gg->invModel[1][1];
register float m12=gg->invModel[1][2];
register float m20=gg->invModel[2][0];
register float m21=gg->invModel[2][1];
register float m22=gg->invModel[2][2];
lm->evaluated=1;
if (dlm) {
for (l=dlm->light_list.head; l; l=l->next ) {
dpl_LIGHT *source_p=(dpl_LIGHT *) l->item;
if (source_p->light_type == dpl_light_type_directional) {
/*{{{ transform its direction cosine*/
float sx, sy, sz,
dx, dy, dz;
dest_p->light_type=dpl_light_type_directional;
sx=source_p->position[0];
sy=source_p->position[1];
sz=source_p->position[2];
dx = (sx*m00) + (sy*m10) + (sz*m20);
dy = (sx*m01) + (sy*m11) + (sz*m21);
dz = (sx*m02) + (sy*m12) + (sz*m22);
dest_p->color[0]=source_p->color[0];
dest_p->color[1]=source_p->color[1];
dest_p->color[2]=source_p->color[2];
quick_renorm ( dest_p->direction, dx, dy, dz, 1.0f );
/*
printf ( "evaled lmodel to %f,%f,%f\n",
dest_p->direction[0],
dest_p->direction[1],
dest_p->direction[2] );
*/
dest_ix++;
dest_p++;
if (dest_ix==MAX_CULL_LIGHTS) break;
/*}}} */
}
else if (source_p->light_type == dpl_light_type_ambient) {
/*{{{ do ambience thing*/
lm->ambience[0]=source_p->color[0];
lm->ambience[1]=source_p->color[1];
lm->ambience[2]=source_p->color[2];
/*}}} */
}
/* what about positional ?? */
}
lm->n_lights=dest_ix;
/* printf ("eval_lmodel found %d lights\n", dest_ix ); */
}
}
/*}}} */
#if 0
/*{{{ void light_vertices ( dpl_VERTEX *v,*/
/* this needs a general diffuse_light_structure,
with normal_offset,
rendered_color_offset,
next_offset
and i can then assembly code it
*/
void light_vertices ( dpl_VERTEX *v,
cull_LMODEL *clm,
cull_MATERIAL *cm,
float normfactor,
int n_vertices )
{
float mtl_r=cm->diffuse[0]*255.0f;
float mtl_g=cm->diffuse[1]*255.0f;
float mtl_b=cm->diffuse[2]*255.0f;
float ar=clm->ambience[0];
float ag=clm->ambience[1];
float ab=clm->ambience[2];
while (v) {
int i, n_lights=clm->n_lights;
float dot;
cull_LIGHT *cl=&clm->lights[0];
float nx=v->normcol[0];
float ny=v->normcol[1];
float nz=v->normcol[2];
float r=ar;
float g=ag;
float b=ab;
if (n_lights<1) goto accum;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<2) goto accum;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<3) goto accum;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<4) goto accum;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<5) goto accum;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<6) goto accum;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<7) goto accum;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
accum:
v->rendered_color[0]=r*mtl_r;
v->rendered_color[1]=g*mtl_g;
v->rendered_color[2]=b*mtl_b;
v=v->next;
}
}
/*}}} */
/*{{{ void light_facets ( dpl_CONNECTION *v,*/
void light_facets ( dpl_CONNECTION *v,
cull_LMODEL *clm,
cull_MATERIAL *cm,
float normfactor,
int n_vertices )
{
float mtl_r=cm->diffuse[0]*255.0f;
float mtl_g=cm->diffuse[1]*255.0f;
float mtl_b=cm->diffuse[2]*255.0f;
float ar=clm->ambience[0];
float ag=clm->ambience[1];
float ab=clm->ambience[2];
while (v) {
float dot;
int i, n_lights=clm->n_lights;
cull_LIGHT *cl=&clm->lights[0];
float nx=v->planeEqn[0];
float ny=v->planeEqn[1];
float nz=v->planeEqn[2];
float r=ar;
float g=ag;
float b=ab;
if (n_lights<1) goto accumf;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<2) goto accumf;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<3) goto accumf;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<4) goto accumf;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<5) goto accumf;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<6) goto accumf;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<7) goto accumf;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
accumf:
v->rendered_color[0]=r*mtl_r;
v->rendered_color[1]=g*mtl_g;
v->rendered_color[2]=b*mtl_b;
v=v->next;
}
}
/*}}} */
#endif
/*{{{ void light_structure ( char *structure,*/
void light_structure ( char *structure,
cull_LMODEL *clm,
cull_MATERIAL *cm,
float normfactor,
int n_vertices,
int normal_offset,
int next_offset,
int rendered_color_offset,
int touched_offset )
{
float mtl_r=cm->diffuse[0]*255.0f;
float mtl_g=cm->diffuse[1]*255.0f;
float mtl_b=cm->diffuse[2]*255.0f;
float ar=clm->ambience[0];
float ag=clm->ambience[1];
float ab=clm->ambience[2];
while (structure) {
if (*(int *)(structure+touched_offset)) {
float dot;
int i, n_lights=clm->n_lights;
cull_LIGHT *cl=&clm->lights[0];
float nx=((float *)(structure+normal_offset))[0];
float ny=((float *)(structure+normal_offset))[1];
float nz=((float *)(structure+normal_offset))[2];
float r=ar;
float g=ag;
float b=ab;
float *rc;
if (n_lights<1) goto accums;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<2) goto accums;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<3) goto accums;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<4) goto accums;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<5) goto accums;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<6) goto accums;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
if (n_lights<7) goto accums;
/*{{{ */
dot=normfactor*((nx*cl->direction[0])+
(ny*cl->direction[1])+
(nz*cl->direction[2]));
if (dot > 0.0f) {
r+=dot*cl->color[0];
g+=dot*cl->color[1];
b+=dot*cl->color[2];
}
cl++;
/*}}} */
/* a goto label ! */
accums:
rc=(float *) (structure+rendered_color_offset);
*rc++=r*mtl_r;
*rc++=g*mtl_g;
*rc++=b*mtl_b;
}
structure = *((char **)(structure+next_offset));
}
}
/*}}} */
/*{{{ cookize_vertices ( dpl_VERTEX *v, int nv )*/
static void
cookize_vertices ( dpl_VERTEX *v, int nv,
cull_MATERIAL *cm )
{
float cook_val=255.0f;
float cook_mtl=31.0f;
float mtl_opacity=cm->diffuse[3];
int i;
float r, g, b, a, r1, g1, b1;
for (i=0; i<nv; i++) {
if (v->touched) {
r=v->normcol[0];
g=v->normcol[1];
b=v->normcol[2];
a=v->normcol[3];
v->rendered_color[0]=cook_val*r;
v->rendered_color[1]=cook_val*g;
v->rendered_color[2]=cook_val*b;
/* damn, have i shagged this or what ? */
v->texcoords[2]=cook_mtl * (1.0f - (a * mtl_opacity));
}
v=v->next;
}
}
/*}}} */
/*}}} */
/*{{{ back-surface culling of goemetries*/
/*{{{ static void clear_vertices ( dpl_VERTEX_LIST *vl, int value )*/
static void clear_vertices ( dpl_VERTEX_LIST *vl, int value )
{
/*
this coding is used rather than while(v) ... v=v->next to avoid
excessive cache-reads when chaining down linked list
warning - DONT CHANGE vertices_per_block!
*/
while (vl) {
vl->vertices[0].touched=value;
vl->vertices[1].touched=value;
vl->vertices[2].touched=value;
vl->vertices[3].touched=value;
vl->vertices[4].touched=value;
vl->vertices[5].touched=value;
vl->vertices[6].touched=value;
vl->vertices[7].touched=value;
vl=vl->next;
}
}
/*}}} */
/*{{{ static void clear_facets ( dpl_CONNECTION_LIST *vl, int value )*/
static void clear_facets ( dpl_CONNECTION_LIST *vl, int value )
{
/*
this coding is used rather than while(v) ... v=v->next to avoid
excessive cache-reads when chaining down linked list
warning - DONT CHANGE vertices_per_block!
*/
while (vl) {
vl->connections[0].touched=value;
vl->connections[1].touched=value;
vl->connections[2].touched=value;
vl->connections[3].touched=value;
vl->connections[4].touched=value;
vl->connections[5].touched=value;
vl->connections[6].touched=value;
vl->connections[7].touched=value;
vl=vl->next;
}
}
/*}}} */
/*{{{ static void solve ( dpl_CONNECTION_LIST *cl, dpl_VERTEX_LIST *vl,*/
#define solve_plane(point,plane) \
(point[dpl_X]*plane[dpl_X])+(point[dpl_Y]*plane[dpl_Y])+(point[dpl_Z]*plane[dpl_Z])+(plane[dpl_W]*point[dpl_W])
#define solve_plane_points(point,px,py,pz,pw) \
(point[dpl_X]*px)+(point[dpl_Y]*py)+(point[dpl_Z]*pz)+(point[dpl_W]*pw)
extern void solve_fn ( dpl_CONNECTION_LIST *cl,
dpl_POINT view );
static void solve ( dpl_CONNECTION_LIST *cl,
dpl_POINT view )
{
/*
solve viewpoint with plane eqn, flagging each triangle as needing
to be drawn or not, and flagging each vertex as needing to be xformed
or not
note to deal with back-facing triangles we call this with all 4
coordinates of VIEW negated
This takes 72 ticks to accept a triangle, 31 ticks to reject,
average execution time 1uS per triangle
*/
int i, j;
register float px=view[0], py=view[1], pz=view[2], pw=view[3];
dpl_CONNECTION *c;
c=&cl->connections[0];
while (c) {
if (solve_plane_points(c->planeEqn,px,py,pz,pw) > 0.0f) {
/* flag this triangle as needed */
c->touched=1;
/* flag all my vertices as needed */
c->indices[0]->touched=1;
c->indices[1]->touched=1;
c->indices[2]->touched=1;
for (j=3; j<c->n_verts; j++) {
c->indices[j]->touched=1;
}
}
else {
/* flag this triangle as not needed */
c->touched=0;
}
c=c->next;
}
}
/*}}} */
/*}}} */
/*{{{ projecting and clipping of geometries*/
/*{{{ clipping ?*/
/*
I feel some optimized triangle clipping coming on. Currently, if
i have to clip i just bite the bullet and fire all unprojected
triangles thru the clipper and then project the clipped output.
However, I should be able to do something more optimal by scanning
the vertex list, and touching any vertices which are behind the
near clip plane.
The correct algorithm is - determine which triangles need clipping,
and clip them, and untouch them. Project all still touched vertices.
Call draw_geometry as normal. This order of operation guarantees that
i dont accidentally project a vertex which will be needed for
subsequent clipping. It may involve so many traversals of the
connection list that its a pain in the butt, BUT it will probably
still turn out cheaper than splitting out all triangles, potentially
clipping them, then passing them thru the projector.
*/
/*}}} */
/*{{{ clipping !*/
/*
quit the bugshit. clipping is always gruesome, dicking with too many
pointers and too many selctive memcpies for my liking. and anyway, the
code is optimized for avoiding clipping at all costs, so when it
happens, who cares if it costs a lot.
so, when clipping polygon geometry, everything is reduced to triangles.
triangles in, triangles out.
so the clipper needs to know
a) the triangle function, the opcode, the material code
b) the incoming triangle
c) the incoming vertices
and generates a set of outgoing vertices (note a triangle becomes at
most a quad, i am just clipping against 1 plane)
*/
/*}}} */
/*{{{ variables to aid clipping and projection*/
static dpl_VERTEX_LIST *clip_vertices=NULL;
static dpl_CONNECTION_LIST *clip_connections=NULL;
/* this is the john rhoades voodoo .... which appears shagged ? huh ? */
float sub_pixel_correct= 0.0f; /* 1024.0f*1024.0f; */
float Czscale=1.04857588E+06f;
/*}}} */
/*{{{ static void clip_vertex_copy ( dpl_VERTEX *dest, dpl_VERTEX *src )*/
static void clip_vertex_copy ( dpl_VERTEX *dest, dpl_VERTEX *src )
{
float *d, *s;
d=dest->texcoords; s=src->texcoords;
*d++=*s++;
*d++=*s++;
*d++=*s++;
d=dest->xform_posn; s=src->xform_posn;
*d++=*s++;
*d++=*s++;
*d++=*s++;
*d++=*s++;
d=dest->rendered_color; s=src->rendered_color;
*d++=*s++;
*d++=*s++;
*d++=*s++;
}
/*}}} */
/*{{{ and_project ( cull_VIEW *eye,*/
static void
and_project ( cull_VIEW *eye,
cull_GEOGROUP *cull_g,
dpl_VERTEX_LIST *vl )
{
register float sx;
register float sy;
register float sz;
register float john_rhoades_sub= sub_pixel_correct,
width_eye_d = eye->screen_half_width*eye->d,
height_eye_d = eye->screen_half_height*eye->d,
Czscale_eye_d = eye->d*eye->zscale*Czscale;
register float shx=(eye->screen_half_width *(eye->shift_x+1.0f))+john_rhoades_sub;
register float shy=(eye->screen_half_height*(eye->shift_y+1.0f))+john_rhoades_sub;
register dpl_VERTEX *v=&vl->vertices[0];
register int i, t, nv=vl->n_vertices;
for (i=0; i<nv; i++ ) {
sx =v->xform_posn[0];
sy =v->xform_posn[1];
sz =1.0f / v->xform_posn[2];
v->xform_posn[0] = ((sx*width_eye_d *sz)+shx) - john_rhoades_sub;
v->xform_posn[1] = ((sy*height_eye_d*sz)+shy) - john_rhoades_sub;
v->xform_posn[2] = sz*Czscale_eye_d;
v=v->next;
}
}
/*}}} */
/*{{{ xform_and_project ( cull_GEOGROUP *cull_g,*/
/* declare assembly-coded version */
extern void
xform_and_project_fn ( cull_VIEW *eye,
cull_GEOGROUP *cull_g,
dpl_VERTEX_LIST *vl );
static void
xform_and_project ( cull_VIEW *eye,
cull_GEOGROUP *cull_g,
dpl_VERTEX_LIST *vl )
{
register float sx;
register float sy;
register float sz;
register float m00=cull_g->forward[0][0];
register float m01=cull_g->forward[0][1];
register float m02=cull_g->forward[0][2];
register float m10=cull_g->forward[1][0];
register float m11=cull_g->forward[1][1];
register float m12=cull_g->forward[1][2];
register float m20=cull_g->forward[2][0];
register float m21=cull_g->forward[2][1];
register float m22=cull_g->forward[2][2];
register float m30=cull_g->forward[3][0];
register float m31=cull_g->forward[3][1];
register float m32=cull_g->forward[3][2];
register float john_rhoades_sub= sub_pixel_correct,
width_eye_d = eye->screen_half_width*eye->d,
height_eye_d = eye->screen_half_height*eye->d,
Czscale_eye_d = eye->d*eye->zscale*Czscale,
dx, dy;
register float shx=(eye->screen_half_width *(eye->shift_x+1.0f))+john_rhoades_sub;
register float shy=(eye->screen_half_height*(eye->shift_y+1.0f))+john_rhoades_sub;
register dpl_VERTEX *v=&vl->vertices[0];
register int i, t, nv=vl->n_vertices;
for (i=0; i<nv; i++ ) {
sx =v->position[0];
sy =v->position[1];
sz =v->position[2];
dx = (sx*m00) + (sy*m10) + (sz*m20) + m30;
dy = (sx*m01) + (sy*m11) + (sz*m21) + m31;
sz = 1.0f /
((sx*m02) + (sy*m12) + (sz*m22) + m32);
v->xform_posn[0] = ((dx*width_eye_d *sz)+shx) - john_rhoades_sub;
v->xform_posn[1] = ((dy*height_eye_d*sz)+shy) - john_rhoades_sub;
v->xform_posn[2] = sz*Czscale_eye_d;
v=v->next;
}
}
/*}}} */
/*{{{ xform ( cull_GEOGROUP *cull_g,*/
static void
xform ( cull_VIEW *eye,
cull_GEOGROUP *cull_g,
dpl_VERTEX_LIST *vl )
{
register float m00=cull_g->forward[0][0];
register float m01=cull_g->forward[0][1];
register float m02=cull_g->forward[0][2];
register float m10=cull_g->forward[1][0];
register float m11=cull_g->forward[1][1];
register float m12=cull_g->forward[1][2];
register float m20=cull_g->forward[2][0];
register float m21=cull_g->forward[2][1];
register float m22=cull_g->forward[2][2];
register float m30=cull_g->forward[3][0];
register float m31=cull_g->forward[3][1];
register float m32=cull_g->forward[3][2];
register float sx;
register float sy;
register float sz;
register float dx, dy, *d;
register int i, nv=vl->n_vertices;
dpl_VERTEX *v=&vl->vertices[0];
for (i=0; i<nv; i++ ) {
if (v->touched) {
d=v->xform_posn;
sx =v->position[0];
sy =v->position[1];
sz =v->position[2];
d[0] = (sx*m00) + (sy*m10) + (sz*m20) + m30;
d[1] = (sx*m01) + (sy*m11) + (sz*m21) + m31;
d[2] = (sx*m02) + (sy*m12) + (sz*m22) + m32;
}
v=v->next;
}
}
/*}}} */
/*{{{ static int do_clipping ( dpl_VERTEX **p1, dpl_VERTEX **p2, int draw_mode )*/
static int do_clipping ( dpl_VERTEX *out,
dpl_VERTEX **p1,
dpl_VERTEX **p2,
float edge,
int draw_mode )
{
register float v1, v2, vv1, vv2;
register int i, outn=0, b1, b2;
#define clipperize(f,ix,t) \
out->f[ix]=(*p1)->f[ix]+(t*(((*p2)->f[ix])-((*p1)->f[ix])))
vv1=(*p1)->xform_posn[dpl_Z];
v1=vv1-edge;
b1=(v1>=0);
for (i = 0; i<3; i++ ) {
vv2=(*p2)->xform_posn[dpl_Z];
v2=vv2-edge;
b2=(v2>=0);
if (b1 && b2) {
/*{{{ clip vertex copy in-line*/
{
float *d, *s;
d=out->texcoords; s=(*p2)->texcoords;
*d++=*s++;
*d++=*s++;
*d++=*s++;
d=out->xform_posn; s=(*p2)->xform_posn;
*d++=*s++;
*d++=*s++;
*d++=*s++;
*d++=*s++;
d=out->rendered_color; s=(*p2)->rendered_color;
*d++=*s++;
*d++=*s++;
*d++=*s++;
}
/*}}} */
/* clip_vertex_copy ( out, (*p2) ); */
out++; outn++;
}
else {
if (b2||b1) {
/*{{{ intersect*/
float t;
t = (edge - vv1) / (vv2 - vv1);
out->xform_posn[2]=edge;
clipperize ( xform_posn, X, t );
clipperize ( xform_posn, Y, t );
/* the shaded alpha - sorry ! */
clipperize ( texcoords, 2, t );
if (draw_mode & dpl_draw_textured) {
clipperize ( texcoords, 0, t );
clipperize ( texcoords, 1, t );
}
else if (draw_mode & dpl_draw_3dtextured) {
clipperize ( texcoords, 0, t );
clipperize ( texcoords, 1, t );
}
if (draw_mode & (dpl_draw_smooth|dpl_draw_colored)) {
clipperize ( rendered_color, 0, t );
clipperize ( rendered_color, 1, t );
clipperize ( rendered_color, 2, t );
clipperize ( rendered_color, 3, t );
}
/*}}} */
out++; outn++;
}
if (b2) {
/*{{{ clip vertex copy in-line*/
{
float *d, *s;
d=out->texcoords; s=(*p2)->texcoords;
*d++=*s++;
*d++=*s++;
*d++=*s++;
d=out->xform_posn; s=(*p2)->xform_posn;
*d++=*s++;
*d++=*s++;
*d++=*s++;
*d++=*s++;
d=out->rendered_color; s=(*p2)->rendered_color;
*d++=*s++;
*d++=*s++;
*d++=*s++;
}
/*}}} */
/* clip_vertex_copy ( out, (*p2)); */
out++; outn++;
}
}
vv1=vv2; v1=v2; p1=p2; b1=b2; p2++;
}
return outn;
}
/*}}} */
/*{{{ clip_polygon ( int *icoeff_pp,*/
static void
clip_triangle ( int *icoeff_pp,
int *icoeff_basep,
dpl_CONNECTION *conn,
dpl_VERTEX *va,
dpl_VERTEX *vb,
dpl_VERTEX *vc,
cull_VIEW *eye,
cull_GEOGROUP *cull_g,
int backwards,
vpx_geometry_function vpx,
int opcode0,
float codeword )
{
int icoeff_p=*icoeff_pp;
int icoeff_base=*icoeff_basep;
float edge=eye->hither;
dpl_CONNECTION *clipcon=&clip_connections->connections[0];
dpl_VERTEX *tri[3],
*out=&clip_vertices->vertices[0];
int outn;
tri[0]=va; tri[1]=vb; tri[2]=vc;
/* if (cull_g->draw_mode & (dpl_draw_smooth|dpl_draw_colored) == 0) { */
clipcon->rendered_color[0]=conn->rendered_color[0];
clipcon->rendered_color[1]=conn->rendered_color[1];
clipcon->rendered_color[2]=conn->rendered_color[2];
/* } */
outn=do_clipping ( out, &tri[2], &tri[0], edge, cull_g->draw_mode );
/*
okee dokee - here we have outn vertices in clipped_vertices,
all ready to be draw
*/
if (outn > 2) {
if (icoeff_p > icoeff_base) {
icoeff_p=(int) next_coeffchunk ();
icoeff_base=icoeff_p + COEFF_FULL;
}
clip_vertices->n_vertices=outn;
and_project ( eye, cull_g, clip_vertices );
clipcon->n_verts=3;
icoeff_p = vpx ( icoeff_p, codeword, opcode0, clipcon, backwards );
if (outn == 4) {
dpl_VERTEX *save=clipcon->indices[1];
if (icoeff_p > icoeff_base) {
icoeff_p=(int) next_coeffchunk ();
icoeff_base=icoeff_p + COEFF_FULL;
}
clipcon->indices[1]=clipcon->indices[2];
clipcon->indices[2]=clipcon->indices[3];
icoeff_p = vpx ( icoeff_p, codeword, opcode0, clipcon, backwards );
clipcon->indices[2]=clipcon->indices[1];
clipcon->indices[1]=save;
}
}
*icoeff_pp=icoeff_p;
*icoeff_basep=icoeff_base;
return;
}
/*}}} */
/*}}} */
/*{{{ drawing geometries*/
/*
typedef int (*vpx_geometry_function)(int,float,int,dpl_CONNECTION*,int );
typedef void (*vpx_totalgeom_function)(int**,float,int,dpl_CONNECTION*,int,int );
icoeff_p = vpx ( icoeff_p, codeword, opcode0, conn, backwards );
*/
/*{{{ draw_total_geometry ( cull_GEOGROUP *cull_g,*/
static void
draw_total_geometry ( dpl_GEOMETRY *g,
int backwards,
vpx_totalgeom_function vpx,
int opcode0,
float codeword )
{
vpx ( &coefficient_ptr, codeword, opcode0,
&g->connections->connections[0],
backwards,
g->connections->n_connections );
}
/*}}} */
/*{{{ draw_unclipped_geometry ( cull_GEOGROUP *cull_g,*/
static void
draw_unclipped_geometry ( dpl_GEOMETRY *g,
int backwards,
vpx_geometry_function vpx,
int opcode0,
float codeword )
{
/*{{{ locals*/
int icoeff_p =(int) coefficient_ptr;
int icoeff_base=COEFF_FULL + (int) last_coeffchunk;
int i, nv=g->connections->n_connections;
dpl_CONNECTION *conn=&g->connections->connections[0];
/*}}} */
for ( i=0; i<nv; i++ ) {
if (conn->touched) {
if (icoeff_p > icoeff_base) {
icoeff_p=(int) next_coeffchunk ();
icoeff_base=icoeff_p + COEFF_FULL;
}
icoeff_p = vpx ( icoeff_p, codeword, opcode0, conn, backwards );
}
conn=conn->next;
}
coefficient_ptr=(float *) icoeff_p;
}
/*}}} */
/*{{{ draw_hither_clipped_geometry ( cull_GEOGROUP *cull_g,*/
static void
draw_hither_clipped_geometry ( cull_GEOGROUP *cull_g,
dpl_GEOMETRY *g,
int backwards,
cull_VIEW *eye,
vpx_geometry_function vpx,
int opcode0,
float codeword )
{
/*{{{ locals*/
float hither=eye->hither;
int icoeff_p =(int) coefficient_ptr;
int icoeff_base=COEFF_FULL + (int) last_coeffchunk;
int i, j, nv=g->connections->n_connections;
dpl_CONNECTION *conn =&g->connections->connections[0];
dpl_CONNECTION *clipcon=&clip_connections->connections[0];
/*}}} */
for ( i=0; i<nv; i++ ) {
if (conn->touched) {
int behinds, verts;
dpl_VERTEX **vp;
dpl_VERTEX *destp;
/*{{{ how many vertices in polygon straddle near clip plane?*/
vp=&conn->indices[0];
for (behinds=0, verts=conn->n_verts; verts; verts--) {
behinds+=((*vp)->xform_posn[2] < hither);
vp++;
}
/*}}} */
if (behinds == 0) {
/*{{{ all beyond near clip, can safely project and draw the poly*/
if (icoeff_p > icoeff_base) {
icoeff_p=(int) next_coeffchunk ();
icoeff_base=icoeff_p + COEFF_FULL;
}
vp =&conn->indices[0];
destp=&clip_vertices->vertices[0];
for (verts=conn->n_verts; verts; verts--) {
clip_vertex_copy ( destp, *vp );
vp++;
destp++;
}
/* if (cull_g->draw_mode & (dpl_draw_smooth|dpl_draw_colored) == 0) { */
clipcon->rendered_color[0]=conn->rendered_color[0];
clipcon->rendered_color[1]=conn->rendered_color[1];
clipcon->rendered_color[2]=conn->rendered_color[2];
/* } */
/* now make sure project does right no of vertices */
clip_vertices->n_vertices=conn->n_verts;
/* and make sure triangle_fn does right no of vertices */
clipcon->n_verts=conn->n_verts;
and_project ( eye, cull_g, clip_vertices );
icoeff_p = vpx ( icoeff_p, codeword, opcode0, clipcon, backwards );
/*}}} */
}
else if (behinds < (verts=conn->n_verts)) {
/*{{{ clip and draw the poly*/
for (j=1; j<verts-1; j++ )
clip_triangle ( &icoeff_p, &icoeff_base,
conn,
conn->indices[0],
conn->indices[j],
conn->indices[j+1],
eye, cull_g, backwards,
vpx, opcode0, codeword );
/*}}} */
}
}
conn=conn->next;
}
coefficient_ptr=(float *) icoeff_p;
}
/*}}} */
/*{{{ draw_yon_clipped_geometry ( cull_GEOGROUP *cull_g,*/
static void
draw_yon_clipped_geometry ( dpl_GEOMETRY *g,
int backwards,
cull_VIEW *eye,
vpx_geometry_function vpx,
int opcode0, float codeword )
{
/*{{{ locals*/
float yon=eye->d*eye->zscale*Czscale / eye->yon;
int icoeff_p =(int) coefficient_ptr;
int icoeff_base=COEFF_FULL + (int) last_coeffchunk;
int i, nv=g->connections->n_connections;
dpl_CONNECTION *conn=&g->connections->connections[0];
/*}}} */
for ( i=0; i<nv; i++ ) {
if (conn->touched) {
int v, verts=conn->n_verts;
dpl_VERTEX **vp=&conn->indices[0];
for (v=0; v<verts; v++) {
/*{{{ if a single vertex closer than yon, draw poly => GOTO IN HERE!*/
/* NOTE > since we are in 1/z perspective space */
if ((*vp)->xform_posn[2] > yon) {
if (icoeff_p > icoeff_base) {
icoeff_p=(int) next_coeffchunk ();
icoeff_base=icoeff_p + COEFF_FULL;
}
icoeff_p = vpx ( icoeff_p, codeword, opcode0, conn, backwards );
goto drawn_it;
}
/*}}} */
}
drawn_it: ;
}
conn=conn->next;
}
coefficient_ptr=(float *) icoeff_p;
}
/*}}} */
/*}}} */
/*{{{ draw_geogroup ( cull_GEOGROUP *gg )*/
static void
draw_geogroup ( cull_VIEW *eye,
cull_GEOGROUP *cull_gg,
cull_LMODEL *cull_lm )
{
/*{{{ some offsets for nasty hand-coded shading function*/
#define VERTEX_NORMAL_OFFSET 16
#define VERTEX_NEXT_OFFSET 44
#define VERTEX_RENDCOLOR_OFFSET 64
#define VERTEX_TOUCHED_OFFSET 76
#define FACET_NORMAL_OFFSET 32
#define FACET_NEXT_OFFSET 0
#define FACET_RENDCOLOR_OFFSET 48
#define FACET_TOUCHED_OFFSET 60
/*}}} */
/*{{{ locals*/
dpl_GEOGROUP *g_grp=cull_gg->geo;
cull_MATERIAL *fm, *bm;
dpl_list *list;
vpx_geometry_function vpx, vpx_b;
int opcode0, opcode0_b;
float codeword, codeword_b;
int drawmode=cull_gg->draw_mode;
int clipcode=cull_gg->clip_code;
/*}}} */
/* printf ("draw geogroup, drawmode 0x%x\n", drawmode ); */
/*{{{ do very late evaluation of lmodel*/
if (cull_lm->evaluated==0)
eval_lmodel ( cull_lm, cull_gg );
/*}}} */
/*{{{ set up polygon drawing functions*/
if (drawmode & dpl_draw_front)
vpx = vpx_drawstuff ( &codeword, &opcode0,
cull_gg, &cull_gg->front_mtl_data );
if (drawmode & dpl_draw_back)
vpx_b = vpx_drawstuff ( &codeword_b, &opcode0_b,
cull_gg, &cull_gg->back_mtl_data );
/*}}} */
fm=&cull_gg->front_mtl_data;
bm=&cull_gg->back_mtl_data;
for (list=g_grp->geometry_list.head; list; list=list->next) {
dpl_GEOMETRY *g=(dpl_GEOMETRY *) list->item;
vpx_geometry_function usevpx_f=vpx, usevpx_b=vpx_b;
/*{{{ modify function based on opacity*/
if (g->variable_alpha) {
/*{{{ f*/
if (vpx == (vpx_geometry_function) tri_zb_rgb)
usevpx_f = (vpx_geometry_function) tri_zb_rgb; /* not impl yet ! */
else if (vpx == (vpx_geometry_function) tri_zb_rgb_t)
usevpx_f = (vpx_geometry_function) tri_zb_rgb_o_t;
/*}}} */
/*{{{ and b*/
if (vpx_b == (vpx_geometry_function) tri_zb_rgb)
usevpx_b = (vpx_geometry_function) tri_zb_rgb; /* not impl yet ! */
else if (vpx_b == (vpx_geometry_function) tri_zb_rgb_t)
usevpx_b = (vpx_geometry_function) tri_zb_rgb_o_t;
/*}}} */
}
/*}}} */
if (drawmode & dpl_draw_front) {
/*{{{ do the front faces, solve with real eye*/
Cdelta_u=fm->du;
Cdelta_v=fm->dv;
clear_vertices ( g->vertices, 0 );
solve ( g->connections, cull_gg->xform_eye );
if ((drawmode & (dpl_draw_smooth | dpl_draw_colored)) == 0)
light_structure ( (char *) &g->connections->connections[0],
cull_lm,
fm, 1.0f,
g->connections->n_connections,
FACET_NORMAL_OFFSET,
FACET_NEXT_OFFSET,
FACET_RENDCOLOR_OFFSET,
FACET_TOUCHED_OFFSET );
else if (drawmode & dpl_draw_smooth)
light_structure ( (char *) &g->vertices->vertices[0],
cull_lm,
fm, 1.0f,
g->vertices->n_vertices,
VERTEX_NORMAL_OFFSET,
VERTEX_NEXT_OFFSET,
VERTEX_RENDCOLOR_OFFSET,
VERTEX_TOUCHED_OFFSET );
else if (drawmode & dpl_draw_colored)
cookize_vertices ( &g->vertices->vertices[0],
g->vertices->n_vertices,
fm );
if (clipcode & clip_hither) {
xform ( eye, cull_gg, g->vertices );
draw_hither_clipped_geometry ( cull_gg, g, 0, eye,
usevpx_f, opcode0, codeword );
}
else {
xform_and_project_fn ( eye, cull_gg, g->vertices );
/*
if (clipcode & clip_yon)
draw_yon_clipped_geometry ( cull_gg, g, 0, eye,
usevpx_f, opcode0, codeword );
else
draw_unclipped_geometry ( cull_gg, g, 0,
usevpx_f, opcode0, codeword );
*/
draw_unclipped_geometry ( g, 0,
usevpx_f, opcode0, codeword );
}
/*}}} */
}
if (drawmode & dpl_draw_back) {
/*{{{ do the back faces, solve with -eye, flip the normals*/
Cdelta_u=bm->du;
Cdelta_v=bm->dv;
clear_vertices ( g->vertices, 0 );
solve ( g->connections, cull_gg->back_xf_eye );
if ((drawmode & (dpl_draw_smooth | dpl_draw_colored)) == 0) {
light_structure ( (char *) &g->connections->connections[0],
cull_lm,
bm, -1.0f,
g->connections->n_connections,
FACET_NORMAL_OFFSET,
FACET_NEXT_OFFSET,
FACET_RENDCOLOR_OFFSET,
FACET_TOUCHED_OFFSET );
}
else if (drawmode & dpl_draw_smooth) {
light_structure ( (char *) &g->vertices->vertices[0],
cull_lm,
bm, -1.0f,
g->vertices->n_vertices,
VERTEX_NORMAL_OFFSET,
VERTEX_NEXT_OFFSET,
VERTEX_RENDCOLOR_OFFSET,
VERTEX_TOUCHED_OFFSET );
}
else if (drawmode & dpl_draw_colored) {
cookize_vertices ( &g->vertices->vertices[0],
g->vertices->n_vertices,
bm );
}
if (clipcode & clip_hither) {
xform ( eye, cull_gg, g->vertices );
draw_hither_clipped_geometry ( cull_gg, g, 1, eye,
usevpx_b, opcode0_b, codeword_b );
}
else {
xform_and_project_fn ( eye, cull_gg, g->vertices );
/*
if (clipcode & clip_yon)
draw_yon_clipped_geometry ( cull_gg, g, 1, eye,
usevpx_b, opcode0_b, codeword_b );
else
*/
draw_unclipped_geometry ( g, 1,
usevpx_b, opcode0_b, codeword_b );
}
/*}}} */
}
}
}
/*}}} */
/*{{{ int *veloci_draw ( cull_VIEW *v )*/
static
int *veloci_draw ( cull_VIEW *v )
{
/*
The draw process - reads each displaylist item in turn, if item is
an lmodel, it is evaluated and becomes the current lmodel. If item
is a geogroup it is lit with the current lmodel
*/
ggroup_render_chunk *chunk;
char *cp;
cull_GEOGROUP *gg;
cull_LMODEL *lm=NULL;
int i, last;
chunk=v->geogroup_head;
if (chunk) {
do {
last=chunk->terminal;
cp=chunk->ggroup_data;
for(i=0; i<chunk->ggroup_count; i++ ) {
gg=(cull_GEOGROUP *) cp;
if (gg->identifier == dpl_type_geogroup) {
draw_geogroup ( v, gg, lm );
cp+=ggroup_bump_val;
}
else if (gg->identifier == dpl_type_lmodel) {
lm=(cull_LMODEL *) cp;
cp+=lmodel_bump_val;
}
else {
printf ("ERROR - bad displaylist tag 0x%x\n", gg->identifier);
return;
}
}
chunk=chunk->next;
} while (last==0);
}
}
/*}}} */
/*{{{ void veloci_rasterize ( int *dma_ptr )*/
static void
veloci_rasterize ( int *dma_ptr )
{
/* printf ("velocirasterize dataptr 0x%x\n", dma_ptr ); */
return;
}
/*}}} */
/*{{{ void veloci_swap_buffers ( int wait_for_retrace )*/
static void
veloci_swap_buffers ( int wait_for_retrace )
{
/* printf ("velociswapbuffers wait_for_retrace=%d\n", wait_for_retrace ); */
flip_screens ( 2, 2 );
return;
}
/*}}} */
extern void reinit_screenbins ( int, int, int );
int animate_time_0,
animate_time;
float animate_elapsed_time=0;
/*{{{ void vr_draw_scene ()*/
void
vr_draw_scene ( int double_buffered )
{
dpl_list *eyetem;
dpl_POINT origin;
int then, now, cull;
/*
printf ("vr_draw_scene, view head=0x%x\n",
the_scene.view_list.head );
*/
if (clip_vertices==NULL) {
/*{{{ allocate + init clip vertex memory*/
int i;
dpl_CONNECTION *con;
dpl_VERTEX *vert;
clip_vertices =(dpl_VERTEX_LIST *) malloc(sizeof(dpl_VERTEX_LIST));
clip_connections=(dpl_CONNECTION_LIST *) malloc(sizeof(dpl_CONNECTION_LIST));
clip_vertices->next=NULL;
clip_connections->next=NULL;
clip_connections->n_connections=1;
con=&clip_connections->connections[0];
vert=&clip_vertices->vertices[0];
for (i=0; i<DPL_CONNECTIONS_PER_BLOCK; i++ ) {
con->indices[i]=&clip_vertices->vertices[i];
}
for (i=0; i<DPL_VERTICES_PER_BLOCK; i++ ) {
dpl_VERTEX *prev=vert;
vert++;
prev->next=vert;
}
/*}}} */
dN_timer ( &animate_time_0 );
}
dN_timer ( &animate_time );
animate_elapsed_time=(animate_time - animate_time_0) / 1.0e6f;
origin[0]=0.0f;
origin[1]=0.0f;
origin[2]=0.0f;
origin[3]=1.0f;
for (eyetem=the_scene.view_list.head;eyetem;eyetem=eyetem->next ) {
dpl_VIEW *eye=(dpl_VIEW *) eyetem->item;
if (eye) {
cull_VIEW *v;
int *dma_ptr;
dN_timer(&then);
v=veloci_cull ( eye, origin );
dN_timer(&cull);
dma_ptr=veloci_draw ( v );
veloci_rasterize ( dma_ptr );
dN_timer(&now);
}
}
veloci_swap_buffers ( double_buffered );
}
/*}}} */