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

1830 lines
52 KiB
C++

/*{{{ banner*/
/*
File eof.c
project pazpl5
author pja
date 7th july 1993
(c) DIVISION limited 1993
This is the end-of-frame code for pazpl5.
*/
/*}}} */
/*{{{ about this code*/
/*
There are 2 end-of-frame sequences - end-of-frame, and end-of-texture
As we enter end-of-frame processing, we have a pixel map as defined in
divpxmap.h, containing colour, texture id and material property
information. The main task performed at end-of-frame is the texture
perspective divide, and the subsequent computation of texel address.
The perspective divide is in fact 2 divides - u and v are both divided
by homo, then coalesced to form the texel address. This is then added to
the texture base address (texture id << 12) to yield the texel look-up
address. Immediately this has been written into pixelmemory:0..23 we can
sequence the texture lookup - in fact we should perform the divide,
coalesce the texel offset into the homo coordinate, execute a pxpl5
'wait for pixel transfer to be complete' opcode, then do a
copy 16 bits of texel offset to pixel memory, clear next 16 bits of
pixel memory, then add into bits 12..20 the texture id. We have a full
texel address, and we can execute a 'do texture lookup' opcode. At this
point we know we have the end-of-frame area free to write into, and we
can copy the shading variables into the end-of-frame area, and proceed
with polygon processing for the next tile. Copying the shading variables
involves doing just copies, but the location of the copy is dependent on
the type of pixel - rgb pixels are copied straight into the accumulation
buffer, but 16-bit intrinsic pixels are multiplied by the 8-bit diffuse
lighting channel (and possibly by the light colour?) before being dropped
into the accumulation area. The remainder of the u and v coordinates are then
copied into the sub-u and sub-v areas, and the 8 bits of specular lighting
are written into end-of-frame space.
When the texture lookup is complete, the opcode sequence is interrupted,
and effectively a DMA engine subroutine call is performed. At this point we
have a 24-bit texture value in pixelmemory:0..23, and the end-of-frame
shading variables in locations dvpx_eofr (see divpxmap.h). The 30-bit
accumulation area only has 24 used bits at this point, and we need the
other 6. We have to turn any 6-bit interpolated textures into 24-bit values -
the first step is to bilinterp to compute an 8-bit modulator. We then need to
pull in a selection of ramps, and select the right one. I suspect I cant
support more than 8 ramps (3 extra bits of end-of-frame material); this
will allow black/white (fine for stuff like wood; brightness modulate yellow)
and blue/white (sky) - i cant think of another 6, so that's enough. We pull
in 8 raps, each of 24-bits (12 upper bits, 12 lower bits), and linterp
between upper and lower, to yield a 24-bit scalar.
If these operations are organised to yield a 30-bit accumulation buffer, we
can accumulate in-place.
We now multiply the 24-bit diffuse colour (in end-of-frame space) by the
24-bit texture look-up value.
We have now freed up the 24-bit diffuse slot, and can download the colour of
the light into this. We now multiply the specular value by the colour of the
light, and add this into the accumulation area, shifting the results down
into the lower 24-bits of the word.
And that is it - we have 24-bits of pixel memory for dumping into a
framestore
*/
/*}}} */
/*{{{ includes*/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "divpxmap.h"
#include "dmaengn.h"
#include "pxpl5typ.h"
#include "..\dpltypes.h"
#include "..\culltype.h"
#include "\projects\dbi0150\dbi0151\ucode\igc_opco.h"
#include "\projects\dbi0150\dbi0151\ucode\igc_comm.h"
/*}}} */
/*{{{ int *tblcpy ( int *dst, int *src )*/
int *tblcpy ( int *dst, int *src )
{
int *p=dst;
while ((*src & 0x80000000) == 0)
*p++ = *src++;
*p++=*src;
return p;
}
/*}}} */
int pxpl5_ticks=0;
int random_index=0;
/* start of frame code */
/*{{{ int *configEMCshi ( int *coeffptr, int x0, int y0 )*/
int *configEMCs_hi ( int *coeffptr, int x0, int y0 )
{
/*{{{ magic table*/
int EMC[] = {
0x2,0x0,0xA,0x8,0x12,0x10,0x1A,0x18,
0x3,0x1,0xB,0x9,0x13,0x11,0x1B,0x19,
0x6,0x4,0xE,0xC,0x16,0x14,0x1E,0x1C,
0x7,0x5,0xF,0xD,0x17,0x15,0x1F,0x1D
};
/*}}} */
int XbAhi, XbBhi, XbAlo, XbBlo, Yb, scalar;
int i, x=0;
Yb = (y0 >> 7) & 0xf;
/*{{{ walk in x coord*/
for ( i=0; i<32; i++ ) {
/*{{{ */
x = EMC[i] + x0;
XbAlo = x & 0x7f; /* bottom 7 bits of XbA */
XbBlo = (x+32) & 0x7f; /* bottom 7 bits of XbB */
XbAhi = (x >> 7) & 0xf; /* top 4 bits of XbA */
XbBhi = ((x+32) >> 7) & 0xf; /* top 4 bits of XbB */
scalar = (Yb<<22) |
XbAlo |
(XbBlo << 7) |
(XbAhi << 14) |
(XbBhi << 18);
/*}}} */
IGC_SEPCFG_S1 ( coeffptr, i, 26, scalar );
/*x0++; */
}
/*}}} */
/*{{{ loads of noops*/
for (i=0; i<4; i++ )
IGC_NOOP ( coeffptr );
return coeffptr;
/*}}} */
}
/* CT */
/* 0 1 2 3 */
/* 0 2 8 3 10 6 18 7 */
/* E 1 0 9 1 11 4 19 5 */
/* M 2 A A B 12 E 1A F */
/* C 3 8 B 9 13 C 1B D */
/* 4 18 C 19 14 1C 1C 1D */
/* 5 16 B 17 15 1A 1B 1B */
/* 6 20 E 21 16 24 1E 25 */
/* 7 1E F 1D 17 24 1F 25 */
/*}}} */
/*{{{ int *configEMCs ( int *coeffptr, int x0, int y0 )*/
int *configEMCs ( int *coeffptr, int x0, int y0 )
{
/*
we need to specify
Yb = bottom of Y in units of 128
XbA = left of A pixel bank
XbB = left of B pixel bank
pixel banks are separated by 32 pixels, A is lower.
Yb is a 4-bit field, in bits 22..25
XbA is 11 bits, split into 7+4. lower 7 in bits 0..6, upper 4 in 14..17
XbB is 11 bits, split into 7+4. lower 7 in bits 7..13, upper 4 in 18..21
This code caters for the 4-way, 8-stedped interleave of EMC->screen
space - the EMC ordering on-screen is 0, 8, 16, 24, 1, 9, 17 etc
*/
int XbAhi, XbBhi, XbAlo, XbBlo, Yb, scalar;
int i, EMCbase=0, EMCtick=0, lastEMCbase=0;
Yb = (y0 >> 7) & 0xf;
for ( i=0; i<32; i++ ) {
XbAlo = x0 & 0x7f; /* bottom 7 bits of XbA */
XbBlo = (x0+32) & 0x7f; /* bottom 7 bits of XbB */
XbAhi = (x0 >> 7) & 0xf; /* top 4 bits of XbA */
XbBhi = ((x0+32) >> 7) & 0xf; /* top 4 bits of XbB */
scalar = (Yb<<22) |
XbAlo |
(XbBlo << 7) |
(XbAhi << 14) |
(XbBhi << 18);
IGC_SEPCFG_S1 ( coeffptr, EMCbase, 26, scalar );
EMCbase+=8;
EMCtick++;
if (EMCtick == 4) {
lastEMCbase++;
EMCbase=lastEMCbase;
EMCtick=0;
}
x0++;
}
for (i=0; i<4; i++ )
IGC_NOOP ( coeffptr );
return coeffptr;
}
/*}}} */
/*{{{ int init_screenbin ( binchunk *firstbin,*/
int init_screenbin ( binchunk *firstbin,
int pixel_x,
int pixel_y, int hires )
{
/*{{{ what we do*/
/*
this function drops the start-of-frame coefficients into the head binchunk
of the screenbin.
There is a fifo latency problem, and we can just make this coefficient
list sufficiently long that we a) init the tile and also b) eat up
the latency to guarantee operation
In order to minimize eaten-up space, I shall drop the coefficients
into the binchunk itself. I need to keep around 8 64-bit words free,
for patching up, which leaves 500+ words of instructions.
The DMA opcode sequence is -
SEND ( startup, startup_words )
GOTO ( .after_startup_words )
.... put startup words here
:after_starup_words )
*/
/*}}} */
/*{{{ locals*/
int *DMAptr = &firstbin->DMA_opcodes[0];
int *DMAptr0 = DMAptr;
int *coeffptr = &DMAptr[64];
int *coeff0;
int t, bytes, words, i, branchAddr, *texdnAddr;
int backGND_offset=0;
/*}}} */
coeff0=coeffptr;
if ((int) coeff0 & 31) {
printf ("MISALIGNED ! ! ! ! ! coeff0 = 0x%x\n", coeff0 );
}
/*{{{ do 'start of tile' code*/
/* set up FBITs at the beginning of each tile */
IGC_FBITS ( coeffptr, 15 );
/* wait for tree to stabilize */
for (i=0; i<4; i++ ) {
IGC_NOOP ( coeffptr );
}
/* tell EMC array where they are on screen */
if (hires)
coeffptr=configEMCs_hi ( coeffptr, pixel_x, pixel_y );
else
coeffptr=configEMCs ( coeffptr, pixel_x, pixel_y );
/*{{{ linear feedback register opacity*/
#define bump(save,length)save++; if (save==length) save=0;
IGC_SETENABS ( coeffptr );
/*
IGC_TREEintoMEM_L3 ( coeffptr, dvpx_texu, 20, 1.0f, 1024.0f, 0.0f );
*/
random_index=((int) coeffptr - (int) coeff0) >> 2;
/*
*/
IGC_TREEintoMEM_L3 ( coeffptr, dvpx_texu, 7, -1.0f, 0.0f, 0.0f );
IGC_TREEintoMEM_L3 ( coeffptr, dvpx_texu+7, 15, 0.0f, 1.0f, 0.0f );
{
int tap0, tap1, tap2, tap3, save, length, base;
base=dvpx_texu;
length=12;
save=0;
tap0=0;
tap1=1;
tap2=4;
tap3=6;
for (i=0; i<length/2; i++) {
int ix0, ix1;
ix0=base+i;
ix1=base+((length - 1) - i);
/* reverse order of bits in word */
IGC_MEMintoENAB ( coeffptr, ix0 );
IGC_ENABxoreqMEM ( coeffptr, ix1 );
IGC_ENABintoMEM ( coeffptr, ix0 );
IGC_MEMintoENAB ( coeffptr, ix0 );
IGC_ENABxoreqMEM ( coeffptr, ix1 );
IGC_ENABintoMEM ( coeffptr, ix1 );
}
for (i=0; i<length; i++) {
IGC_MEMintoENAB ( coeffptr, base+tap0 );
IGC_ENABxoreqMEM ( coeffptr, base+tap1 );
IGC_ENABxoreqMEM ( coeffptr, base+tap2 );
IGC_ENABxoreqMEM ( coeffptr, base+tap3 );
IGC_ENABintoMEM ( coeffptr, base+save );
bump (save, length );
bump (tap0, length );
bump (tap1, length );
bump (tap2, length );
bump (tap3, length );
}
}
IGC_SETENABS ( coeffptr );
IGC_CPY ( coeffptr, dvpx_opacity, dvpx_texu+7, dvpx_opacitybits );
IGC_MEMgeSCA_S1 ( coeffptr, dvpx_opacity, dvpx_opacitybits, 29 );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_opacity, dvpx_opacitybits, 29 );
#undef bump
/*}}} */
/* a few more NOOPs for good measure */
for (i=0; i<4; i++ ) {
IGC_NOOP ( coeffptr );
}
/*}}} */
/*{{{ note how much code we have generated*/
/* count up how much store we have used */
bytes=(int) coeffptr - (int) coeff0;
words=bytes >> 3; /* make into 64-bit count */
/*}}} */
/* these become GOTO next tile */
*DMAptr++=(int) 0;
*DMAptr++=(int) 0;
*DMAptr++=(int) coeff0;
*DMAptr++=DMA_SEND(words);
branchAddr = (int) coeff0 + (words << 3);
*DMAptr++=branchAddr;
*DMAptr++=DMA_GOTO_VAL;
firstbin->usage=(int) branchAddr - (int) DMAptr0;
firstbin->DMA_opcodes[63]=firstbin->usage;
return (backGND_offset >> 2);
}
/*}}} */
/* end of frame / texture code */
int *texture_table_iptr=NULL;
extern cull_RAMP texture_ramps[MAX_TEX_RAMPS];
int *tile_poke_address;
/*{{{ static int *linterp ( int *coeffptr,*/
static int *linterp ( int *coeffptr,
int result,
int op1, int op2, int alpha,
int resultbits,
int oplen, int alphalen )
{
/*
NB alphabits must be < resultbits
*/
int i, reduced_adds;
IGC_SETENABS ( coeffptr );
IGC_CLEAR ( coeffptr, result, resultbits );
if ((oplen + alphalen) < resultbits) {
reduced_adds=0;
result+=resultbits-(oplen+alphalen);
}
else {
reduced_adds=(alphalen+oplen) - resultbits;
op2+=reduced_adds;
op1+=reduced_adds;
oplen-=reduced_adds;
}
for (i=0; i<reduced_adds; i++ ) {
IGC_MEMintoENAB ( coeffptr, alpha );
IGC_MEMpluseqMEM ( coeffptr, result, op2, oplen+1, oplen );
IGC_MEMBARintoENAB ( coeffptr, alpha );
IGC_MEMpluseqMEM ( coeffptr, result, op1, oplen+1, oplen );
op1--;
op2--;
alpha++;
oplen++;
}
for (i=reduced_adds; i<alphalen; i++) {
IGC_MEMintoENAB ( coeffptr, alpha );
IGC_MEMpluseqMEM ( coeffptr, result, op2, oplen+1, oplen );
IGC_MEMBARintoENAB ( coeffptr, alpha );
IGC_MEMpluseqMEM ( coeffptr, result, op1, oplen+1, oplen );
alpha++;
result++;
}
return coeffptr;
}
/*}}} */
/*{{{ static int *multuu_unc ( int *coeffptr,*/
static int *multuu_unc ( int *coeffptr,
int res, int Ua, int Ub, int Rlen, int Ualen, int Ublen )
/************************************************************************
**
** multuu() - unsigned Result <- Unsigned x Unsigned. All in pixel memory.
** Result length must be >= both operand lengths.
**
************************************************************************/
{
int i, j, k;
IGC_SETENABS(coeffptr);
IGC_CLEAR(coeffptr, res, Rlen);
j = k = Ublen - Rlen + Ualen;
if (Ublen >= Ualen) {
for(i = 0; i < k; i++ ){
IGC_MEMintoENAB (coeffptr, Ua +i);
IGC_MEMpluseqMEM(coeffptr, res, Ub +j, Rlen, Ublen -j);
j--;
}
i=k;
while (i < Ualen) {
IGC_MEMintoENAB (coeffptr, Ua +i);
IGC_MEMpluseqMEM(coeffptr, res +j, Ub, Rlen -j, Ublen);
i++, j++;
}
}
else {
for(i = 0; i < k; i++ ){
IGC_MEMintoENAB(coeffptr, Ub +i);
IGC_MEMpluseqMEM(coeffptr, res, Ua +j, Rlen, Ualen -j);
j--;
}
i=k;
while (i < Ublen) {
IGC_MEMintoENAB(coeffptr, Ub +i);
IGC_MEMpluseqMEM(coeffptr, res +j, Ua, Rlen -j, Ualen);
i++, j++;
}
}
return coeffptr;
}
/*}}} */
static char* send_pass="zilch";
/*{{{ int *send_em ( int **DMAref, int **coeffref, int *coeff0, int flush )*/
static
int *send_em ( int **DMAref, int **coeffref, int *coeff0, int flush, int max_long )
{
int *coeffptr=*coeffref;
int *DMAptr =*DMAref;
int words, longwords;
words=((int) coeffptr - (int) coeff0) >> 2;
longwords = words >> 1;
/* pad coefficient stream to ensure 64-bit boundary */
if ((flush && (longwords > 0)) || (longwords > max_long)) {
if (words & 1) {
IGC_NOOP ( coeffptr );
longwords++;
}
/*
printf ("send(%d, %s) : DMAptr 0x%x %d words from 0x%x\n",
flush, send_pass, DMAptr, longwords, coeff0 );
*/
if (longwords > 127) {
/*
*/
printf ("WARNING - long SEND\n" );
*DMAptr++=(int) (coeff0);
*DMAptr++=DMA_SEND(120);
longwords-=120;
coeff0+=240;
}
*DMAptr++=(int) coeff0;
*DMAptr++=DMA_SEND(longwords);
coeffptr = (int *) ((31 + (int) (coeffptr)) & ~31);
*DMAref=DMAptr;
*coeffref=coeffptr;
return coeffptr;
}
else {
return coeff0;
}
}
/*}}} */
/*
stuff for perspective division of textures. perspective divides does
the full-precision divide, transpective divide does the limited precision
transparent texture divide
*/
/*{{{ static void texdivide ( int **DMAref, int **coeffRef,*/
static void texdivide ( int **DMAref,
int **coeffRef,
int *coeff0,
int num,
int denom,
int sigbits )
{
/*
this texdivide operates in-place - the numerator is replaced by
its perspective divided version.
*/
int i, res, divbits;
int *coeffptr=*coeffRef;
int *DMAptr =*DMAref;
send_pass="texdivide";
res =num+dvpx_texubits - 1;
divbits=dvpx_texubits;
for (i=0; i<sigbits; i++ ) {
IGC_SETENABS ( coeffptr );
IGC_MEMgeMEM ( coeffptr, num, denom, divbits );
IGC_MEMminuseqMEM ( coeffptr, num, denom, divbits, divbits );
IGC_ENABintoMEM ( coeffptr, res );
res--, denom++, divbits--;
}
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 30 );
*DMAref=DMAptr;
*coeffRef=coeff0;
}
/*}}} */
/*{{{ void perspective_divides ( int **DMAref, int** coeffRef )*/
void perspective_divides ( int **DMAref, int** coeffRef )
{
/*
this is the first operation done at the end-of-frame for a given tile
we do not hit the i/o area, since it is potentially active (we have
not yet BSWAITed, but we are guaranteed to have done
the end-of-texture opcodes
*/
int *coeffptr=*coeffRef;
int *DMAptr=*DMAref;
int *coeff0 =coeffptr;
int *coeff00=coeffptr;
int i, words;
/*
printf ("coeffptr for perspective at 0x%x DMAptr at 0x%x\n",
coeffptr, DMAptr );
*/
#if divlogo
/*{{{ put division logo into bottom right of screen*/
{
/* NB only works if texture id=0, size=64, mode=point */
float x0=532.0f, x1=660.0f,
y0=382.0f, y1=440.0f;
float u0=0.001, u1=0.999f,
v0=0.999, v1=0.001f;
float du_dx=(u1-u0) / (x1-x0);
float dv_dy=(v1-v0) / (y1-y0);
float zscale=(1<<(dvpx_texzbits - 3)) * 0.999f;
float uscale=(1<<(dvpx_texubits - 3)) * 0.999f;
float uC=(x0*du_dx) - u0;
float vC=(y0*dv_dy) - v0;
/*
IGC_SETENABS ( coeffptr );
*/
IGC_MEMintoENAB ( coeffptr, dvpx_opaque_50 );
IGC_TREEgeZERO_L3 ( coeffptr, 1.0f, 0.0f, -x0 );
IGC_TREEltZERO_L3 ( coeffptr, 1.0f, 0.0f, -x1 );
IGC_TREEgeZERO_L3 ( coeffptr, 0.0f, 1.0f, -y0 );
IGC_TREEltZERO_L3 ( coeffptr, 0.0f, 1.0f, -y1 );
/* put texture u into memory */
IGC_TREEintoMEM_L3 ( coeffptr,
dvpx_texu,
dvpx_texubits,
du_dx*uscale, 0, -uC*uscale );
/* put texture v into memory */
IGC_TREEintoMEM_L3 ( coeffptr,
dvpx_texv,
dvpx_texvbits,
0, dv_dy*uscale, -vC*uscale );
/* put texture z into memory */
IGC_TREEintoMEM_C1 ( coeffptr,
dvpx_texz,
dvpx_texzbits,
8.0f*zscale );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_scalar, dvpx_intrinsic-dvpx_scalar,
1 | (4<<1) ); /* patch to indicate texture */
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_r24, 24, 0xffffff );
}
/*}}} */
#endif
IGC_SETENABS ( coeffptr );
/* lose 1 bit of precision in texz (required by divide) */
IGC_CLEAR ( coeffptr, dvpx_texz+dvpx_texzbits, 1 );
/* 16 bits of result == 3 (0 .. 7.990), 8 (0 .. 255), 5 sub-texel bits */
texdivide ( &DMAptr, &coeffptr, coeff0,
dvpx_texu,
dvpx_texz+1,
17 );
coeff0=coeffptr;
texdivide ( &DMAptr, &coeffptr, coeff0,
dvpx_texv,
dvpx_texz+1,
17 );
coeff0=coeffptr;
*coeffRef=coeffptr;
*DMAref =DMAptr;
}
/*}}} */
/*{{{ void transpective_divides ( int **DMAref, int** coeffRef )*/
void transpective_divides ( int **DMAref, int** coeffRef )
{
/*
this does the limited-precision perspective divides for
transparent texturing
we do not hit the i/o area, since it is potentially active (we have
not yet BSWAITed, but we are guaranteed to have done
the end-of-texture opcodes
*/
int *coeffptr=*coeffRef;
int *DMAptr=*DMAref;
int *coeff0 =coeffptr;
int *coeff00=coeffptr;
int i, words;
/*
printf ("coeffptr for perspective at 0x%x DMAptr at 0x%x\n",
coeffptr, DMAptr );
*/
IGC_SETENABS ( coeffptr );
/* lose 1 bit of precision in texz (required by divide) */
IGC_CLEAR ( coeffptr, dvpx_texz+dvpx_texzbits, 1 );
/* 11 bits of result == 3 (0 .. 7.990), 8 (0 .. 255), 0 sub-texel bits */
/* I AM CONFUSED - why do i have to do 12 ?????? */
texdivide ( &DMAptr, &coeffptr, coeff0,
dvpx_texu,
dvpx_texz+1,
12 );
coeff0=coeffptr;
texdivide ( &DMAptr, &coeffptr, coeff0,
dvpx_texv,
dvpx_texz+1,
13 );
coeff0=coeffptr;
*coeffRef=coeffptr;
*DMAref =DMAptr;
}
/*}}} */
#if 0
/*{{{ old sphere stuff - dont chunk this*/
/*{{{ static int* smokey_circle ( int *coeffptr, float xc, float yc, float r, int dark )*/
static int* smokey_circle ( int *coeffptr,
float xc, float yc, float r, int dark )
{
/*
scan-convert - g(x,y) = Ax + By + C - Q
A = 2a, B = 2b C = r2 - a2 - b2, Q = x2 + y2
*/
float fA, fB, fC, fD, fE, fF;
int affect_pixel=dvpx_texz;
fD=-1.0f;
fE= 0.0f;
fF=-1.0f;
fA=xc*2.0f;
fB=yc*2.0f;
fC=(r*r) - ((xc*xc) + (yc*yc));
IGC_SETENABS ( coeffptr );
IGC_TREEgeZERO_Q6 ( coeffptr, fA, fB, fC, fD, fE, fF );
IGC_ENABintoMEM ( coeffptr, dvpx_enblpush );
/* enblpush says i am in the circle */
IGC_ENABandeqMEM ( coeffptr, dvpx_pixcolourtype );
IGC_ENABintoMEM ( coeffptr, affect_pixel );
IGC_MEMgtSCA_S1 ( coeffptr, dvpx_r24, 8, dark );
IGC_MEMpluseqSCA_S1 ( coeffptr, dvpx_r24, dvpx_r24, 8, (0xff & (-dark)));
IGC_ENABINV ( coeffptr );
IGC_ENABandeqMEM ( coeffptr, affect_pixel );
IGC_CLEAR ( coeffptr, dvpx_r24, 8 );
IGC_MEMintoENAB ( coeffptr, affect_pixel );
IGC_MEMgtSCA_S1 ( coeffptr, dvpx_g24, 8, dark );
IGC_MEMpluseqSCA_S1 ( coeffptr, dvpx_g24, dvpx_g24, 8, (0xff & (-dark)));
IGC_ENABINV ( coeffptr );
IGC_ENABandeqMEM ( coeffptr, affect_pixel );
IGC_CLEAR ( coeffptr, dvpx_g24, 8 );
IGC_MEMintoENAB ( coeffptr, affect_pixel );
IGC_MEMgtSCA_S1 ( coeffptr, dvpx_b24, 8, dark );
IGC_MEMpluseqSCA_S1 ( coeffptr, dvpx_b24, dvpx_b24, 8, (0xff & (-dark)));
IGC_ENABINV ( coeffptr );
IGC_ENABandeqMEM ( coeffptr, affect_pixel );
IGC_CLEAR ( coeffptr, dvpx_b24, 8 );
IGC_MEMintoENAB ( coeffptr, dvpx_enblpush );
IGC_ENABandeqMEMBAR ( coeffptr, dvpx_pixcolourtype );
IGC_ENABintoMEM ( coeffptr, affect_pixel );
/*{{{ do diff*/
IGC_MEMgtSCA_S1 ( coeffptr, dvpx_diffuse, 8, dark );
IGC_MEMpluseqSCA_S1 ( coeffptr, dvpx_diffuse, dvpx_diffuse, 8, (0xff & (-dark)));
IGC_ENABINV ( coeffptr );
IGC_ENABandeqMEM ( coeffptr, affect_pixel );
IGC_CLEAR ( coeffptr, dvpx_diffuse, 8 );
/*}}} */
/*{{{ do spec*/
IGC_MEMintoENAB ( coeffptr, affect_pixel );
IGC_MEMgtSCA_S1 ( coeffptr, dvpx_specular, 8, dark );
IGC_MEMpluseqSCA_S1 ( coeffptr, dvpx_specular, dvpx_specular, 8, (0xff & (-dark)));
IGC_ENABINV ( coeffptr );
IGC_ENABandeqMEM ( coeffptr, affect_pixel );
IGC_CLEAR ( coeffptr, dvpx_specular, 8 );
/*}}} */
return coeffptr;
}
/*}}} */
/*{{{ int *scan_dot ( int *coeffptr, int slot, float x, float y, float r,*/
int *scan_dot ( int *coeffptr,
int slot,
float x, float y, float r,
float lx, float ly, float lz )
{
float fA, fB, fC, fD, fE, fF, r2=r*r;
float K, r_invlz;
r_invlz=r/lz;
K=-255.99f*lz/r2;
fF=-1.0f;
fD=fF;
fE=0;
fA=(x*2.0f) - (lx*r_invlz);
fB=(y*2.0f) - (ly*r_invlz);
fC=(r2) - ((x*x) + (y*y)) + (lx*x*r_invlz) + (ly*y*r_invlz);
fA*=K;
fB*=K;
fC*=K;
fD*=K;
fE*=K;
fF*=K;
IGC_TREEgeZERO_Q6 ( coeffptr, fA, fB, fC, fD, fE, fF );
IGC_TREEclmpintoMEM_Q0 ( coeffptr, slot, 8 );
return coeffptr;
}
/*}}} */
/*{{{ int *sphere ( float x, float y, float rad )*/
int *sphere ( int *coeffptr,
float x,
float y,
float z,
float r,
float rz,
float lx,
float ly,
float lz,
int intrinsic )
{
/*
scan-convert - g(x,y) = Ax + By + C - Q
A = 2a, B = 2b C = r2 - a2 - b2, Q = x2 + y2
Note that r is screen-space radius,
rz is radius in z-buffer space
d SAME AS f FOR SQUARE PIXEL DISPLAYS
*/
float two=2.0f, fA, fB, fC, fD;
float r2=r*r,
x2y2=(x*x)+(y*y),
r12=1.0f/r2;
float K, r_invlz;
r2-=x2y2;
fA=x*two;
fB=y*two;
fC=r2;
fD=-1.0f;
/* switch on pixels inside circle */
IGC_SETENABS ( coeffptr );
IGC_TREEgeZERO_Q6 ( coeffptr, fA, fB, fC, fD, 0.0f, fD );
/* z-buffer pixels */
K=rz*r12;
fA*=K;
fB*=K;
fC=(z+rz)-(x2y2*K);
fD=-K;
IGC_MEMltTREE_Q6 ( coeffptr, dvpx_zbuf, dvpx_zbufbits,
fA, fB, fC, fD, 0.0f, fD );
IGC_TREEclmpintoMEM_Q0 ( coeffptr, dvpx_zbuf, dvpx_zbufbits );
/* shade pixels */
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_scalar, dvpx_scalarbits, intrinsic );
IGC_CLEAR ( coeffptr, dvpx_diffuse, 16 );
r_invlz=r/lz;
K=-255.99f*lz*r12;
lx*=r_invlz;
ly*=r_invlz;
fA=K*((x*two) - lx);
fB=K*((y*two) - ly);
fC=K*(r2 + (lx*x + ly*y));
fD=-K;
IGC_TREEgeZERO_Q6 ( coeffptr, fA, fB, fC, fD, 0.0f, fD );
IGC_TREEclmpintoMEM_Q0 ( coeffptr, dvpx_specular, 8 );
return coeffptr;
}
/*}}} */
/*}}} */
#endif
/*{{{ end of frame variables*/
int eof_backR=90,
eof_backG=110,
eof_backB=190,
eof_farZ=30,
eof_doFOG=0,
eof_FOG_rval=81,
eof_FOG_gval=61,
eof_FOG_bval=31;
float eof_FOG_near= 5000.0f,
eof_FOG_far = 10000.0f;
int eof_Z_near = 65536,
eof_Z_far = 20;
/*}}} */
/*{{{ explode4 ( int *coeffptr, int where4, int where8, int enbl )*/
int *
explode4 ( int *coeffptr, int where4, int where8, int enbl )
{
/*
IGC_MEMintoENAB ( coeffptr, enbl );
IGC_CLEAR ( coeffptr, where8, 8 );
IGC_MEMeqONES ( coeffptr, where4+2, 2 );
IGC_SET ( coeffptr, where8+7, 1 );
IGC_CPY ( coeffptr, where8+5, where4, 2 );
IGC_MEMintoENAB ( coeffptr, enbl );
IGC_MEMeqSCA_S1 ( coeffptr, where4+2, 2, 0x2 );
IGC_SET ( coeffptr, where8+6, 1 );
IGC_CPY ( coeffptr, where8+4, where4, 2 );
IGC_MEMintoENAB ( coeffptr, enbl );
IGC_MEMeqSCA_S1 ( coeffptr, where4+2, 2, 0x1 );
IGC_SET ( coeffptr, where8+5, 1 );
IGC_CPY ( coeffptr, where8+3, where4, 2 );
IGC_MEMintoENAB ( coeffptr, enbl );
IGC_MEMeqZERO ( coeffptr, where4+2, 2 );
IGC_SET ( coeffptr, where8+4, 1 );
IGC_CPY ( coeffptr, where8+2, where4, 2 );
*/
IGC_MEMintoENAB ( coeffptr, enbl );
IGC_CLEAR ( coeffptr, where8, 4 );
IGC_CPY ( coeffptr, where8+4, where4, 4 );
return coeffptr;
}
/*}}} */
/*{{{ static void end_of_texture ( int **DMAref, int** coeffRef )*/
static void end_of_texture ( int **DMAref, int** coeffRef )
{
/*
NOTE that we have done the BSWAIT and the perspective
divide before entering here - dvpx_texu and texv hold real u and
v parametrics to index a texture map
*/
int *coeffptr=*coeffRef;
int *DMAptr =*DMAref;
int *coeff0 =coeffptr;
int *coeff00 =coeffptr;
int words, i;
send_pass="end_of_texture";
/* *****************************************
all below here may use ONLY end-of-frame space
********************************************* */
/*{{{ notes on vwe format*/
/*
Implement 8 texture formats -
000 = bits 20..23 \
001 = bits 16..19 \ monochrome
010 = bits 12..15 / modulators, contrast tbd
011 = bits 8..11 /
100 = bits 8..16 8-bit monochrome
101 = bilinear interp
110 = bits 8..16 3:3:2 color
111 = bits 12..23 4:4:4 floating-point color
magic combination of id==64, size == 256x256 indicates dont texture
So option is, do we use floating-point format for 4-bit monochrome,
or do we just flat-map with big 16-level contours. The 4-bit table is
4 5 6 7 8 10 12 14 16 20 24 28 32 40 48 56
16 20 24 30 32 40 48 56 64 80 96 112 128 160 192 224
an alternate 5-bit table uses just 1 fp bit -
8 9 10 11 12 13 14 15 16 18 20 22 24 26 28 30
64 72 80 88 96 104 112 120 128 144 160 176 192 208 224 240
or
*/
/*}}} */
/* the all-important bswait */
IGC_BSWAIT ( coeffptr );
/*{{{ bilinear zoom into 8 top bits for lerp*/
/* bilinear h-pass, bottom left <-> bottom right */
coeffptr = linterp ( coeffptr,
dvpx_io+24, dvpx_io, dvpx_io+6, dvpx_eofsubu,
8, 6, 5 );
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x5 );
IGC_CPY ( coeffptr, dvpx_io, dvpx_io+26, 6 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/* bilinear h-pass, top left <-> top right */
coeffptr = linterp ( coeffptr,
dvpx_io+24, dvpx_io+12, dvpx_io+18, dvpx_eofsubu,
8, 6, 5 );
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x5 );
IGC_CPY ( coeffptr, dvpx_io+6, dvpx_io+26, 6 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/* bilinear v-pass */
coeffptr = linterp ( coeffptr,
dvpx_io+24, dvpx_io, dvpx_io+6, dvpx_eofsubv,
8, 6, 5 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/*}}} */
/*{{{ modes 0..4 - copy to top 8-bits for ramp lerp*/
/* 4-bit monochrome bits 20..24 */
IGC_SETENABS ( coeffptr );
IGC_MEMeqZERO ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits );
IGC_SET ( coeffptr, dvpx_io+24, 4 );
IGC_CPY ( coeffptr, dvpx_io+28, dvpx_io+20, 4 );
/* 4-bit monochrome bits 16..20 */
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x1 );
IGC_SET ( coeffptr, dvpx_io+24, 4 );
IGC_CPY ( coeffptr, dvpx_io+28, dvpx_io+16, 4 );
/* 4-bit monochrome bits 12..16 */
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x2 );
IGC_SET ( coeffptr, dvpx_io+24, 4 );
IGC_CPY ( coeffptr, dvpx_io+28, dvpx_io+12, 4 );
/* 4-bit monochrome bits 8..12 */
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x3 );
IGC_SET ( coeffptr, dvpx_io+24, 4 );
IGC_CPY ( coeffptr, dvpx_io+28, dvpx_io+8, 4 );
/* 8-bit monochrome */
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x4 );
IGC_CPY ( coeffptr, dvpx_io+24, dvpx_io+8, 8 );
/*}}} */
/*{{{ clear mode memory*/
IGC_SETENABS ( coeffptr );
IGC_MEMgeSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x6 );
IGC_ENABINV ( coeffptr );
IGC_CLEAR ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits );
/*}}} */
/*{{{ lerp texture ramp*/
/* ************************************************************* */
/* now access the texture colour map table (8 32-bit entries) */
/* cant use tblcpy, as i then cant hack in the entries per frame */
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
IGC_SETENABS ( coeffptr );
IGC_MEMeqZERO ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits );
texture_table_iptr=coeffptr;
for (i=0; i<MAX_TEX_RAMPS; i++ ) {
*coeffptr++ =Ix_TBLENTRY_S1(0,dvpx_eoftexramp,24, dvpx_eoftexrampbits );
*coeffptr++ =P_TBLENTRY(0, dvpx_eoftexramp, 24, dvpx_eoftexrampbits );
*coeffptr++ =texture_ramps[i].codeWord;
}
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/* now linterp from r0 to r1 */
coeffptr = linterp ( coeffptr,
dvpx_eofsubu,
dvpx_io+0, dvpx_io+4, dvpx_io+24, 10, 4, 8 );
IGC_SETENABS ( coeffptr );
IGC_MEMeqZERO ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits );
IGC_CPY ( coeffptr, dvpx_io, dvpx_eofsubu+2, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/* now linterp from g0 to g1 */
coeffptr = linterp ( coeffptr, dvpx_eofsubu,
dvpx_io+8, dvpx_io+12, dvpx_io+24, 10, 4, 8 );
IGC_SETENABS ( coeffptr );
IGC_MEMeqZERO ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits );
IGC_CPY ( coeffptr, dvpx_io+8, dvpx_eofsubu+2, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/* now linterp from b0 to b1 */
coeffptr = linterp ( coeffptr, dvpx_eofsubu,
dvpx_io+16, dvpx_io+20, dvpx_io+24, 10, 4, 8 );
IGC_SETENABS ( coeffptr );
IGC_MEMeqZERO ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits );
IGC_CPY ( coeffptr, dvpx_io+16, dvpx_eofsubu+2, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/*}}} */
/*{{{ full-color formats*/
/* both full-color modes, make a copy of i/o area in sub-u */
/* 8-bit 3-3-2 full color */
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x6 );
IGC_CPY ( coeffptr, dvpx_eofsubu, dvpx_io, 8 );
IGC_CLEAR ( coeffptr, dvpx_io, 24 );
IGC_CPY ( coeffptr, dvpx_io+(16+6), dvpx_eofsubu+6, 2 );
IGC_CPY ( coeffptr, dvpx_io+(8+5), dvpx_eofsubu+3, 3 );
IGC_CPY ( coeffptr, dvpx_io+(0+5), dvpx_eofsubu, 3 );
/* 12-bit 4-4-4 full color */
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x7 );
IGC_CPY ( coeffptr, dvpx_eofsubu, dvpx_io, 8 );
IGC_ENABintoMEM ( coeffptr, dvpx_eofsubu+9 );
coeffptr = explode4 ( coeffptr, dvpx_io+8, dvpx_io+16, dvpx_eofsubu+9 );
coeffptr = explode4 ( coeffptr, dvpx_eofsubu+4, dvpx_io+8, dvpx_eofsubu+9 );
coeffptr = explode4 ( coeffptr, dvpx_eofsubu, dvpx_io, dvpx_eofsubu+9 );
/*
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_eoftexmode, dvpx_eoftexmodebits, 0x7 );
IGC_CPY ( coeffptr, dvpx_eofsubu, dvpx_io, 8 );
IGC_CLEAR ( coeffptr, dvpx_io+16, 4 );
IGC_CPY ( coeffptr, dvpx_io+20, dvpx_io+8, 4 );
IGC_CLEAR ( coeffptr, dvpx_io+8, 4 );
IGC_CPY ( coeffptr, dvpx_io+12, dvpx_eofsubu+4, 4 );
IGC_CLEAR ( coeffptr, dvpx_io, 4 );
IGC_CPY ( coeffptr, dvpx_io+4, dvpx_eofsubu, 4 );
*/
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/*}}} */
/*{{{ multiply by end-of-frame colour*/
/* use eofsubu and subv, these are now free for scratchpad */
coeffptr=multuu_unc ( coeffptr, dvpx_eofsubu, dvpx_io+16, dvpx_eofb,
10, 8, 8 );
IGC_MEMintoENAB ( coeffptr, dvpx_eoftextured );
IGC_CPY ( coeffptr, dvpx_eofb, dvpx_eofsubu+2, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
coeffptr=multuu_unc ( coeffptr, dvpx_eofsubu, dvpx_io+8, dvpx_eofg,
10, 8, 8 );
IGC_MEMintoENAB ( coeffptr, dvpx_eoftextured );
IGC_CPY ( coeffptr, dvpx_eofg, dvpx_eofsubu+2, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
coeffptr=multuu_unc ( coeffptr, dvpx_eofsubu, dvpx_io, dvpx_eofr,
10, 8, 8 );
IGC_MEMintoENAB ( coeffptr, dvpx_eoftextured );
IGC_CPY ( coeffptr, dvpx_eofr, dvpx_eofsubu+2, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
/*}}} */
/*{{{ DONT copy to io area, IN FACT linterp fog*/
if (eof_doFOG) {
IGC_SETENABS ( coeffptr );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_io+24, 8, eof_FOG_bval );
coeffptr = linterp ( coeffptr,
dvpx_io+14,
dvpx_io+24,
dvpx_eofb,
dvpx_eoffog,
10, 8, 8 ); /* the 8 msbs end up in dvpx_io+16 */
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
IGC_SETENABS ( coeffptr );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_io+24, 8, eof_FOG_gval );
coeffptr = linterp ( coeffptr,
dvpx_io+6,
dvpx_io+24,
dvpx_eofg,
dvpx_eoffog,
10, 8, 8 ); /* ditto dvpx_io+8 */
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
IGC_SETENABS ( coeffptr );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_io+24, 8, eof_FOG_rval );
coeffptr = linterp ( coeffptr,
dvpx_eofg,
dvpx_io+24,
dvpx_eofr,
dvpx_eoffog,
10, 8, 8 );
IGC_SETENABS ( coeffptr );
IGC_CPY ( coeffptr, dvpx_io, dvpx_eofg+2, 8 );
}
else {
IGC_SETENABS ( coeffptr );
IGC_CPY ( coeffptr, dvpx_io, dvpx_eofr, 24 );
}
/*}}} */
/*{{{ and write to VRAM*/
IGC_VRAMWrite ( coeffptr, 4 );
for (i=0; i<4; i++)
IGC_NOOP ( coeffptr );
/*}}} */
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 40 );
words=(int) coeffptr - (int) coeff00;
words>>=3;
/*
printf ("%d 64-bit words in end-of-texture sequence\n", words );
*/
*coeffRef=coeffptr;
*DMAref =DMAptr;
}
/*}}} */
/*{{{ static short_end_of_frame ( int **DMAref, int** coeffRef ) <<< H A C K*/
static void short_end_of_frame ( int **DMAref, int** coeffRef )
{
/*
NOTE that we have done the BSWAIT and the perspective
divide before entering here - dvpx_texu and texv hold real u and
v parametrics to index a texture map
*/
int *coeffptr=*coeffRef;
int *DMAptr =*DMAref;
int *coeff0 =coeffptr;
int *coeff00 =coeffptr;
/*{{{ declare some variables*/
int i, words, edge;
int dotexture= dvpx_opaque_50,
tmp1 = dvpx_opaque_25,
bilinear = dvpx_opaque_12;
/*}}} */
send_pass="end_of_frame";
/* printf ("short end_of_frame : coeffptr 0x%x DMAptr 0x%x\n", coeffptr, DMAptr ); */
/*{{{ turn u,v into SRAM address, save subu,v into eofarea*/
/* a value of 0x3f in texture id and 0x3 in type means
pixel not textured */
IGC_SETENABS ( coeffptr );
IGC_CLEAR ( coeffptr, dvpx_io, 24 );
IGC_CLEAR ( coeffptr, bilinear, 1 );
/* so only if memory == all ones do we not texture */
IGC_MEMeqONES ( coeffptr, dvpx_texsize, dvpx_texsizebits+dvpx_texidbits );
IGC_ENABINV ( coeffptr );
IGC_ENABintoMEM ( coeffptr, dotexture );
for (i=0; i<3; i++ ) {
int id, sububase, subvbase,
ubase, vbase;
edge=6+i;
id = i;
ubase = dvpx_texu+(dvpx_texubits-edge);
vbase = dvpx_texv+(dvpx_texvbits-edge);
sububase = dvpx_texu+(dvpx_texubits-(edge+dvpx_eofsububits));
subvbase = dvpx_texv+(dvpx_texvbits-(edge+dvpx_eofsubvbits));
ubase-=3; /* eliminate wrap bits */
vbase-=3;
sububase-=3;
subvbase-=3;
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_texsize, dvpx_texsizebits, id );
IGC_CPY ( coeffptr, dvpx_io, ubase, edge );
IGC_CPY ( coeffptr, dvpx_io+edge, vbase, edge );
IGC_MEMpluseqMEM ( coeffptr, dvpx_io+12, dvpx_texid,
dvpx_texidbits+1, dvpx_texidbits );
IGC_CPY ( coeffptr, dvpx_eofsubu, sububase, dvpx_eofsububits);
IGC_CPY ( coeffptr, dvpx_eofsubv, subvbase, dvpx_eofsubvbits);
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
}
/*}}} */
/*{{{ trigger Texture Look Up*/
/* trigger texture lookup sequence */
IGC_TextSeq ( coeffptr, 4 );
for (i=0; i<4; i++ )
IGC_NOOP ( coeffptr );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 40 );
/*}}} */
/*{{{ move some variables to eof area*/
IGC_MEMintoENAB ( coeffptr, dotexture );
IGC_ENABintoMEM ( coeffptr, dvpx_eoftextured );
IGC_SETENABS ( coeffptr );
IGC_CPY ( coeffptr, dvpx_eoftexramp, dvpx_texrampsel, dvpx_texrampselbits );
IGC_CPY ( coeffptr, dvpx_eoftexmode, dvpx_texmode, dvpx_texmodebits );
/*}}} */
/*{{{ if z further than far clip, set to backGND*/
IGC_SETENABS ( coeffptr );
IGC_MEMgtSCA_S1 ( coeffptr, dvpx_zbuf, dvpx_zbufbits, eof_farZ );
IGC_ENABINV ( coeffptr );
/* IGC_CLEAR ( coeffptr, dvpx_zbuf, dvpx_zbufbits ); */
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_r24, 8, eof_backR );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_g24, 8, eof_backG );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_b24, 8, eof_backB );
/*}}} */
/*{{{ cheap fog - uses eofrgb as scratchpad, do before ...*/
if (eof_doFOG) {
int sigbits,
basebit,
t=eof_Z_near - eof_Z_far,
scalar;
/* ********************************************************************
OK, here is a no-divides fog algorithm, which needs a multiply
Take as input fog_near and fog_far. Turn these into z-buffer coordinates
by z_near (d*near*2^20 / fog_near) etc. If z>z_near, fog=ff. If z<z_far,
fog =0. otherwise, compute t=z-fog_far, giving a number in range
0..(fog_near-fog_far). We know how many bits are needed to represent this,
so shift down until it occupies 9 bits (in fact, compute a base bit).
Now put a scalar into memory, which is 0.999 / (fog_near-fog_far).
This number is then multiplied by the z-buffer contents, so that, if
z was fog_near, we yield 255, and if z was fog_far, we get 0. In terms
of executed IGC ops, we do a pair of compares and 8-bit writes, a 20-bit
subtract and a 9x9 ==> 10 bit multiply, then an 8-bit copy into fog.
NOTE direction of fog - fog value is 0xff if we are up close,
0x00 if we are fully fogged
*/
IGC_SETENABS ( coeffptr );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_eofr, dvpx_zbufbits, eof_Z_far );
IGC_MEMgeSCA_S1 ( coeffptr, dvpx_zbuf, dvpx_zbufbits, eof_Z_near );
IGC_SET ( coeffptr, dvpx_eoffog, dvpx_eoffogbits );
IGC_ENABINV ( coeffptr );
IGC_ENABintoMEM ( coeffptr, dvpx_opaque_50 );
IGC_MEMgeMEM ( coeffptr, dvpx_eofr, dvpx_zbuf, dvpx_zbufbits );
IGC_CLEAR ( coeffptr, dvpx_eoffog, dvpx_eoffogbits );
IGC_ENABINV ( coeffptr );
IGC_ENABandeqMEM ( coeffptr, dvpx_opaque_50 );
/* we are now enabled if we need fogging */
IGC_ENABintoMEM ( coeffptr, dvpx_opaque_50 );
/* push enable to safety */
IGC_MEMminuseqMEM ( coeffptr, dvpx_zbuf, dvpx_eofr, dvpx_zbufbits, dvpx_zbufbits );
/* now zbuf = zbuf - farz
so the trick now is, how many bits are needed to represent this,
to make the multiply as short as possible ?
*/
sigbits=0;
while (t) {
t>>=1;
sigbits++;
}
/*
so now we know maximum number of significant bits in zbuf - however,
this is potentially misleading; if near-far = 129, then we need 8 bits,
but are almost a factor of 2 off. So we scale up to 255, which involves
scan-converting (255.9f * (1 << sigbits)) / (near - far), a 9-bit number
*/
scalar = (int) ((255.9f * (float) (1 << sigbits)) /
(float) (eof_Z_near - eof_Z_far));
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_eofr, 9, scalar );
/*
printf ("scalar = %d from sigbits of %d\n", scalar, sigbits );
printf ("z near = %d z far = %d difference = %d\n",
eof_Z_near,
eof_Z_far,
eof_Z_near-eof_Z_far );
*/
basebit=(dvpx_zbuf+sigbits) - 9;
coeffptr=multuu_unc ( coeffptr, dvpx_eofg+2, dvpx_eofr, basebit,
10, 9, 9 );
IGC_MEMintoENAB ( coeffptr, dvpx_opaque_50 );
IGC_CPY ( coeffptr, dvpx_eoffog, dvpx_eofg+3, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
}
/*}}} */
/*{{{ ... prepare rgb in dvpx_eofr, g, b*/
IGC_SETENABS ( coeffptr );
IGC_CPY ( coeffptr, dvpx_eofr, dvpx_r24, 24 );
/*}}} */
IGC_CLEAR ( coeffptr, dvpx_zbuf, dvpx_zbufbits );
IGC_CLEAR ( coeffptr, dvpx_scalar, dvpx_scalarbits );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_r24, 8, eof_backR );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_g24, 8, eof_backG );
IGC_SCAintoMEM_S1 ( coeffptr, dvpx_b24, 8, eof_backB );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 40 );
words=(int) coeffptr - (int) coeff00;
words>>=3;
/*
printf ("%d 64-bit words in end-of-frame sequence\n", words );
*/
*coeffRef=coeffptr;
*DMAref =DMAptr;
}
/*}}} */
/*{{{ int short_end_of_frame_DMA ( int *DMAptr, int *coeffptr, int *end_of_tex_DMA )*/
int *wait_poke_address;
int short_end_of_frame_DMA ( int *DMAptr, int *coeffptr, int *end_of_tex_DMA )
{
int *coeff0 =coeffptr;
int *coeff00=coeffptr;
int *DMAptr0=DMAptr;
int i, DMAbytes,
IGCbytes;
coeff0=coeffptr;
perspective_divides ( &DMAptr, &coeffptr );
coeff0=coeffptr;
send_pass="eofDMA";
/* make sure texture sequence has executed */
wait_poke_address=DMAptr+1;
/* NB this flush is hacked into a WAIT after the first tile */
*DMAptr++=0x0;
*DMAptr++=DMA_FLUSH_VAL;
/* reinit semaphore */
*DMAptr++=(int) end_of_tex_DMA;
*DMAptr++=DMA_TXDN_VAL;
/* make sure VRAM write has terminated */
IGC_BSWAIT ( coeffptr );
for (i=0; i<4; i++)
IGC_NOOP ( coeffptr );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 20 );
/* wait for fifo to empty (i.e BSWAIT has executed) */
*DMAptr++=(int) 0;
*DMAptr++=DMA_FLUSH;
*DMAptr++=(int) 0;
*DMAptr++=DMA_FLUSH;
tile_poke_address=DMAptr;
/* set up tile address */
*DMAptr++= 0; /* these are patched ! */
*DMAptr++=DMA_TILE;
short_end_of_frame ( &DMAptr, &coeffptr );
coeff0=coeffptr;
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 20 );
DMAbytes = (int) DMAptr - (int) DMAptr0;
IGCbytes = (int) coeffptr - (int) coeff00;
/*
wait_poke_address=DMAptr+1;
printf ("%d bytes of DMA, %d bytes of IGC in end-of-frame\n",
DMAbytes, IGCbytes );
*/
return (DMAbytes>>2);
}
/*}}} */
/*{{{ int end_of_textr_DMA ( int *DMAptr, int *coeffptr )*/
int end_of_textr_DMA ( int *DMAptr, int *coeffptr )
{
int *coeff0 =coeffptr;
int *coeff00=coeffptr;
int *DMAptr0=DMAptr;
int i, DMAbytes, IGCbytes;
end_of_texture ( &DMAptr, &coeffptr );
coeff0=coeffptr;
*DMAptr++=0;
*DMAptr++=DMA_RETE_VAL;
DMAbytes = (int) DMAptr - (int) DMAptr0;
IGCbytes = (int) coeffptr - (int) coeff00;
/*
printf ("%d bytes of DMA, %d bytes of IGC in end-of-texture\n",
DMAbytes, IGCbytes );
*/
return (DMAbytes>>2);
}
/*}}} */
/*{{{ static void end_of_transptex ( int **DMAref, int** coeffRef )*/
static void end_of_transptex ( int **DMAref, int** coeffRef )
{
/*
NOTE that we have done the BSWAIT and the perspective
divide before entering here - dvpx_texu and texv hold real u and
v parametrics to index a texture map
*/
int *coeffptr=*coeffRef;
int *DMAptr =*DMAref;
int *coeff0 =coeffptr;
int *coeff00 =coeffptr;
int words, i;
send_pass="end_of_transptex";
/* *****************************************
all below here may use ONLY end-of-frame space
********************************************* */
IGC_ENABintoMEM ( coeffptr, dvpx_io + 31 );
/*{{{ should we keep this pixel?*/
/* *************************************
if opaque AND eof_zbuf > zbuf,
replace zbuf,
multiply texture by eofrgb,
replace pixel,
flag pixel type as 24-bit, non-textured
*/
/* lsb of blue is write-enable */
IGC_MEMintoENAB ( coeffptr, dvpx_io+16 );
IGC_MEMgtMEM ( coeffptr, dvpx_eoftranspz, dvpx_zbuf, dvpx_zbufbits );
/*
enable set if a) blue texel write-enable asserted and
b) transp z-buffer closer than current z-buffer
*/
IGC_ENABintoMEM ( coeffptr, dvpx_io+30 ); /* trash this for temp */
/*}}} */
/*{{{ yes - set pixel type*/
/*
NB enable is set if we had a blue write enable AND our eofzbuf is > zbuf
so - force pixel type to be 24-bit, non-textured
*/
IGC_CLEAR ( coeffptr, dvpx_texsize, dvpx_texsizebits );
IGC_CPY ( coeffptr, dvpx_zbuf, dvpx_eoftranspz, dvpx_zbufbits );
/*}}} */
/*{{{ and multiply looked-up texture by end-of-frame colour*/
/* use eofsubu and subv, these are now free for scratchpad */
coeffptr=multuu_unc ( coeffptr, dvpx_eofsubu, dvpx_io+16, dvpx_eofb,
9, 8, 8 );
IGC_MEMintoENAB ( coeffptr, dvpx_io+30 );
IGC_CPY ( coeffptr, dvpx_b24, dvpx_eofsubu+1, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
coeffptr=multuu_unc ( coeffptr, dvpx_eofsubu, dvpx_io+8, dvpx_eofg,
9, 8, 8 );
IGC_MEMintoENAB ( coeffptr, dvpx_io+30 );
IGC_CPY ( coeffptr, dvpx_g24, dvpx_eofsubu+1, 8 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
coeffptr=multuu_unc ( coeffptr, dvpx_eofsubu, dvpx_io, dvpx_eofr,
9, 8, 8 );
IGC_MEMintoENAB ( coeffptr, dvpx_io+30 );
IGC_CPY ( coeffptr, dvpx_r24, dvpx_eofsubu+1, 8 );
/*}}} */
IGC_MEMintoENAB ( coeffptr, dvpx_io + 31 );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 40 );
words=(int) coeffptr - (int) coeff00;
words>>=3;
/*
printf ("%d 64-bit words in end-of-transptex sequence\n", words );
*/
*coeffRef=coeffptr;
*DMAref =DMAptr;
}
/*}}} */
/*{{{ static void end_of_transframe ( int **DMAref, int** coeffRef )*/
int *trans_wait_poke_address;
static void end_of_transframe ( int **DMAref, int** coeffRef )
{
/*
NOTE that we have done the BSWAIT and the perspective
divide before entering here - dvpx_texu and texv hold real u and
v parametrics to index a texture map
*/
int *coeffptr=*coeffRef;
int *DMAptr =*DMAref;
int *coeff0 =coeffptr;
int *coeff00 =coeffptr;
/*{{{ declare some variables*/
int i, words, edge;
/*}}} */
send_pass="end_of_frame";
/*{{{ turn u,v into SRAM address*/
/* a value of 0 in texture type means pixel not textured */
IGC_SETENABS ( coeffptr );
IGC_CLEAR ( coeffptr, dvpx_io, 24 );
IGC_SETENABS ( coeffptr );
IGC_MEMeqZERO ( coeffptr, dvpx_texsize, dvpx_texsizebits );
IGC_CLEAR ( coeffptr, dvpx_zbuf, dvpx_zbufbits );
/*
note the end-of-transparent texture frig - we force our zbuf to
be maximally distant, so no matter what the compare, we lose.
NBB MAKE SURE WE DO A GT, NOT a GE !
*/
for (i=0; i<3; i++ ) {
int id, ubase, vbase;
edge=6+i;
id = (i+1)*2; /* 2 == 64x64 point-24 */
ubase = (dvpx_texu + (dvpx_texubits - edge)) - 3;
vbase = (dvpx_texv + (dvpx_texvbits - edge)) - 3;
IGC_SETENABS ( coeffptr );
IGC_MEMeqSCA_S1 ( coeffptr, dvpx_texsize, dvpx_texsizebits, id );
IGC_CPY ( coeffptr, dvpx_io, ubase, edge );
IGC_CPY ( coeffptr, dvpx_io+edge, vbase, edge );
IGC_MEMpluseqMEM ( coeffptr, dvpx_io+12, dvpx_texid,
dvpx_texidbits+1, dvpx_texidbits );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 0, 40 );
}
/*}}} */
/*{{{ trigger Texture Look Up*/
/* trigger texture lookup sequence */
IGC_TextSeq ( coeffptr, 4 );
for (i=0; i<4; i++ )
IGC_NOOP ( coeffptr );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 40 );
/*}}} */
/*{{{ move zbuffer to eof area*/
IGC_SETENABS ( coeffptr );
IGC_CPY ( coeffptr, dvpx_eoftranspz, dvpx_zbuf, dvpx_zbufbits );
/*}}} */
/*{{{ prepare rgb in dvpx_eofr, g, b*/
IGC_CPY ( coeffptr, dvpx_eofr, dvpx_r24, 24 );
IGC_CLEAR ( coeffptr, dvpx_zbuf, dvpx_zbufbits );
/*}}} */
/* and the code in init_screenbin for the opaque tile does the rest */
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 40 );
words=(int) coeffptr - (int) coeff00;
words>>=3;
*coeffRef=coeffptr;
*DMAref =DMAptr;
}
/*}}} */
/*{{{ int end_of_transframe_DMA ( int *DMAptr, int *coeffptr, int *end_of_tex_DMA )*/
int end_of_transframe_DMA ( int *DMAptr, int *coeffptr,
int *end_of_transptex_DMA )
{
int *coeff0 = coeffptr;
int *coeff00 = coeffptr;
int *DMAptr0 = DMAptr;
int i, DMAbytes,
IGCbytes;
coeff0=coeffptr;
transpective_divides ( &DMAptr, &coeffptr );
coeff0=coeffptr;
send_pass="eofDMA";
/* make sure last opaque texture sequence has executed */
trans_wait_poke_address=DMAptr+1;
*DMAptr++=0x0;
*DMAptr++=DMA_FLUSH_VAL;
/* reinit semaphore */
*DMAptr++=(int) end_of_transptex_DMA;
*DMAptr++=DMA_TXDN_VAL;
/* make sure VRAM write has terminated */
IGC_BSWAIT ( coeffptr );
for (i=0; i<4; i++)
IGC_NOOP ( coeffptr );
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 20 );
/* wait for fifo to empty (i.e BSWAIT has executed) */
*DMAptr++=(int) 0;
*DMAptr++=DMA_FLUSH;
*DMAptr++=(int) 0;
*DMAptr++=DMA_FLUSH;
end_of_transframe ( &DMAptr, &coeffptr );
coeff0=coeffptr;
coeff0=send_em(&DMAptr, &coeffptr, coeff0, 1, 20 );
DMAbytes = (int) DMAptr - (int) DMAptr0;
IGCbytes = (int) coeffptr - (int) coeff00;
return (DMAbytes>>2);
}
/*}}} */
/*{{{ int end_of_transp_DMA ( int *DMAptr, int *coeffptr )*/
int end_of_transp_DMA ( int *DMAptr, int *coeffptr )
{
int *coeff0 =coeffptr;
int *coeff00=coeffptr;
int *DMAptr0=DMAptr;
int i, DMAbytes, IGCbytes;
end_of_transptex ( &DMAptr, &coeffptr );
coeff0=coeffptr;
*DMAptr++=0;
*DMAptr++=DMA_RETE_VAL;
DMAbytes = (int) DMAptr - (int) DMAptr0;
IGCbytes = (int) coeffptr - (int) coeff00;
return (DMAbytes>>2);
}
/*}}} */