📄 dsp4emu.cpp
字号:
project_y2 = project_focaly * plane / view_plane;
// quadratic regression (rough)
if(project_focaly>=-0x0f)
py_dy = project_focaly * project_focaly * -0.20533553
- 1.08330005 * project_focaly - 69.61094639;
else
py_dy = project_focaly * project_focaly * -0.000657035759
- 1.07629051 * project_focaly - 65.69315963;
// approximate # of raster lines
segments = abs(project_y2-project_y1);
// prevent overdraw
if(project_y2>=raster) segments=0;
else raster=project_y2;
// don't draw outside the window
if(project_y2<viewport_top) segments=0;
// project new positions
if(segments>0)
{
// interpolate between projected points
px_dx = ((project_x2-project_x1)<<8)/segments;
}
// debug
++block;
#ifdef PRINT
printf("(line %d) Op0D check %02X, plane %04X\n",c,(uint16)segments,(uint16)(plane));
#endif
// prepare output
DSP4.out_count=8+2+6*segments;
DSP4_WRITE_WORD(0,project_focalx);
DSP4_WRITE_WORD(2,project_x2);
DSP4_WRITE_WORD(4,project_focaly);
DSP4_WRITE_WORD(6,project_y2);
DSP4_WRITE_WORD(8,segments);
#if 0
DSP4_WRITE_WORD(0,-1);
DSP4_WRITE_WORD(2,-1);
DSP4_WRITE_WORD(4,-1);
//DSP4_WRITE_WORD(6,-1);
DSP4_WRITE_WORD(8,-1);
#endif
index=10;
project_x = project_centerx + project_x1;
// iterate through each point
for( lcv=0; lcv<segments; lcv++ )
{
// step through the projected line
y_out = project_y+((py_dy*lcv)>>8);
x_out = project_x+((px_dx*lcv)>>8);
// factor in dynamic track changes
y_out += envelope;
#if 0
project_ptr=-1;
y_out=-1;
x_out=-1;
#endif
// data
DSP4_WRITE_WORD(index+0,project_ptr);
DSP4_WRITE_WORD(index+2,y_out);
DSP4_WRITE_WORD(index+4,x_out);
index += 6;
// post-update
project_ptr -= 4;
}
// post-update
project_y += ((py_dy*lcv)>>8);
if(segments > 0)
{
project_x1 = project_x2;
project_y1 = project_y2;
// track occlusion: can't see anything below it
multi_farplane[multi_index2] = plane;
multi_raster[multi_index2] -= segments;
}
// update focal projection points
project_pitchy += (int8)DSP4.parameters[3];
project_pitchx += (int8)DSP4.parameters[5];
project_focaly += project_pitchy;
project_focalx += project_pitchx;
} while(1);
DSP4.waiting4command = TRUE;
DSP4.out_count = 0;
}
#undef PRINT
#if OP==0x0009
#define PRINT
#endif
#if OP==0x0006
#define PRINT
#endif
void DSP4_Op09()
{
uint16 command;
DSP4.waiting4command = FALSE;
// op flow control
switch(DSP4_Logic) {
case 1: goto resume1; break;
case 2: goto resume2; break;
case 3: goto resume3; break;
case 4: goto resume4; break;
case 5: goto resume5; break;
case 6: goto resume6; break;
case 7: goto resume7; break;
}
////////////////////////////////////////////////////
// process initial inputs
// debug
block=0;
// grab screen information
view_plane = PLANE_START;
center_x = DSP4_READ_WORD(0x00);
center_y = DSP4_READ_WORD(0x02);
// 0x00 = DSP4_READ_WORD(0x04);
viewport_left = DSP4_READ_WORD(0x06);
viewport_right = DSP4_READ_WORD(0x08);
viewport_top = DSP4_READ_WORD(0x0a);
viewport_bottom = DSP4_READ_WORD(0x0c);
#ifdef PRINT2
printf("Window: (%04X,%04X) (%04X,%04X)\n",
viewport_left,viewport_right,viewport_top,viewport_bottom);
#endif
// cycle through viewport window data
multi_index1++;
multi_index1%=4;
goto no_sprite;
do {
////////////////////////////////////////////////////
// check for new sprites
do {
uint16 second;
DSP4.in_count = 4;
DSP4.in_index = 2;
DSP4_WAIT(1) resume1:
// try to classify sprite
second = DSP4_READ_WORD(2);
// op termination
if(second == 0x8000) goto terminate;
second >>= 8;
sprite_type = 0;
// vehicle sprite
if(second == 0x90)
{
sprite_type = 1;
break;
}
// terrain sprite
else if(second != 0)
{
sprite_type = 2;
break;
}
no_sprite:
// no sprite. try again
DSP4.in_count = 2;
DSP4_WAIT(2) resume2:
;
} while (1);
////////////////////////////////////////////////////
// process projection information
sprite_found:
// vehicle sprite
if(sprite_type == 1)
{
int16 plane;
int16 car_left, car_right, car_left_a;
int16 focal_back, focal_front;
uint8 distance, id;
// we already have 4 bytes we want
DSP4.in_count = 6+12;
DSP4.in_index = 4;
DSP4_WAIT(3) resume3:
// filter inputs
project_y1 = DSP4_READ_WORD(0x00);
// 0x9000 = DSP4_READ_WORD(0x02);
id = DSP4.parameters[0x04];
distance = DSP4.parameters[0x05];
focal_back = DSP4_READ_WORD(0x06);
focal_front = DSP4_READ_WORD(0x08);
car_left_a = DSP4_READ_WORD(0x0a);
car_left = DSP4_READ_WORD(0x0c);
plane = DSP4_READ_WORD(0x0e);
car_right = DSP4_READ_WORD(0x10);
// calculate car's x-center
project_focalx = car_right-car_left;
// determine how far into the screen to project
project_focaly = focal_back;
project_x = project_focalx * plane / view_plane;
segments = 0x33 - project_focaly * plane / view_plane;
far_plane = plane;
// prepare memory
sprite_x = center_x+project_x;
sprite_y = viewport_bottom-segments;
far_plane = plane;
// debug
++block;
#ifdef PRINT
printf("(line %d) Op09 vehicle block %d, Loop %04X\n",c,block,(uint16)project_y1);
//printf("%04X %04X %04X %04X / ",focal_back,focal_front,car_left_a,car_left);
//printf("%02X %02X ", distance, id);
#endif
// make the car's x-center available
DSP4.out_count = 2;
DSP4_WRITE_WORD(0,project_focalx);
#if 0
DSP4_WRITE_WORD(0,-1);
#endif
// grab a few remaining vehicle values
DSP4.in_count = 4;
DSP4_WAIT(4) resume4:
// store final values
int height = DSP4_READ_WORD(0);
sprite_offset = DSP4_READ_WORD(2);
// vertical lift factor
sprite_y += height;
#ifdef PRINT_09
printf("%04X\n",sprite_offset);
#endif
}
// terrain sprite
else if(sprite_type == 2)
{
int16 plane;
// we already have 4 bytes we want
DSP4.in_count = 6+6+2;
DSP4.in_index = 4;
DSP4_WAIT(5) resume5:
// sort loop inputs
project_y1 = DSP4_READ_WORD(0x00);
plane = DSP4_READ_WORD(0x02);
project_centerx = DSP4_READ_WORD(0x04);
//project_y1 = DSP4_READ_WORD(0x06);
project_focalx = DSP4_READ_WORD(0x08);
project_focaly = DSP4_READ_WORD(0x0a);
sprite_offset = DSP4_READ_WORD(0x0c);
// determine distances into virtual world
segments = 0x33 - project_y1;
project_x = project_focalx * plane / view_plane;
project_y = project_focaly * plane / view_plane;
// prepare memory
sprite_x = center_x+project_x-project_centerx;
sprite_y = viewport_bottom-segments+project_y;
far_plane = plane;
// debug
++block;
#ifdef PRINT
printf("(line %d) Op09 terrain block %d, Loop %04X\n",c,block,(uint16)project_y1);
#endif
}
// default sprite size: 16x16
sprite_size = 1;
////////////////////////////////////////////////////
// convert tile data to OAM
do {
DSP4.in_count = 2;
DSP4_WAIT(6) resume6:
command = DSP4_READ_WORD(0);
// opcode termination
if(command == 0x8000) goto terminate;
// toggle sprite size
if(command == 0x0000)
{
sprite_size = !sprite_size;
#ifdef PRINT
//printf("TOGGLE=%02X\n",(uint8)sprite_size);
#endif
continue;
}
// new sprite information
command >>= 8;
if(command != 0x20 && command != 0x40 &&
command != 0x60 && command != 0xa0 &&
command != 0xc0 && command != 0xe0)
break;
DSP4.in_count = 6;
DSP4.in_index = 2;
DSP4_WAIT(7) resume7:
/////////////////////////////////////
// process tile data
bool8 clip;
int16 sp_x, sp_y, sp_oam, sp_msb;
int16 sp_dx, sp_dy;
int16 expand = sprite_size ? 15:7;
// sprite deltas
sp_dy = DSP4_READ_WORD(2);
sp_dx = DSP4_READ_WORD(4);
// update coordinates
sp_y = sprite_y + sp_dy;
sp_x = sprite_x + sp_dx;
// reject points outside the clipping window
clip = FALSE;
// window clipping
if(sp_x < viewport_left-expand || sp_x > viewport_right) clip=TRUE;
if(sp_y < viewport_top || sp_y > viewport_bottom) clip=TRUE;
// track occlusion:
// clip any tiles that are below the road
if(far_plane <= multi_farplane[multi_index1] &&
(sp_y>>3) >= (multi_raster[multi_index1]>>3)) clip=TRUE;
// tile limitations
if ((sp_y >= -expand) && ((sp_y < 0) || ((sp_y & 0x01ff) < 0x00eb)) && !clip)
{
short Row = (sp_y >> 3) & 0x1f;
if(!sprite_size)
{
// 1x1 tile
if (RowCount[Row] < MaxTilesPerRow)
RowCount[Row]++;
else
clip=TRUE;
}
else
{
// 2x2 tile
if ((RowCount[Row+0]+1 < MaxTilesPerRow) &&
(RowCount[Row+1]+1 < MaxTilesPerRow))
{
RowCount[Row+0]+=2;
RowCount[Row+1]+=2;
}
else
clip=TRUE;
}
}
#ifdef PRINT
printf("(line %d) %04X, %04X, %04X / %04X %04X\n",line,
(uint16)sp_x,(uint16)sp_y,(uint16)far_plane,(uint16)multi_farplane[multi_index1],(uint16)multi_raster[multi_index1]);
#endif
// don't draw offscreen coordinates
DSP4.out_count = 0;
if(!clip)
{
int16 out_index = 0;
int16 offset = DSP4_READ_WORD(0);
// update sprite nametable/attribute information
sp_oam = sprite_offset + offset;
sp_msb = (sp_x<0 || sp_x>255);
#ifdef PRINT2
printf("(line %d) %04X, %04X, %04X, %04X, %04X\n",line,
(uint16)sp_oam,(uint16)sprite_offset,(uint16)offset,
(uint16)sp_x,(uint16)sp_y);
#endif
// emit transparency information
if(
(sprite_offset&0x08) &&
((sprite_type==1 && sp_y>=0xcc) ||
(sprite_type==2 && sp_y>=0xbb))
)
{
DSP4.out_count = 6;
// one block of OAM data
DSP4_WRITE_WORD(0,1);
// OAM: x,y,tile,no attr
DSP4.output[2] = sp_x&0xFF;
DSP4.output[3] = (sp_y+6)&0xFF;
DSP4_WRITE_WORD(4,0xEE);
out_index = 6;
// OAM: size,msb data
DSP4_Op06(sprite_size,sp_msb);
#if 0
//DSP4_WRITE_WORD(0,-1);
DSP4_WRITE_WORD(2,-1);
DSP4_WRITE_WORD(4,-1);
#endif
}
// normal data
DSP4.out_count += 8;
// one block of OAM data
DSP4_WRITE_WORD(out_index+0,1);
// OAM: x,y,tile,attr
DSP4.output[out_index+2] = sp_x&0xFF;
DSP4.output[out_index+3] = sp_y&0xFF;
DSP4_WRITE_WORD(out_index+4,sp_oam);
// no following OAM data
DSP4_WRITE_WORD(out_index+6,0);
// OAM: size,msb data
DSP4_Op06(sprite_size,sp_msb);
#if 0
//DSP4_WRITE_WORD(out_index+0,-1);
DSP4_WRITE_WORD(out_index+2,-1);
DSP4_WRITE_WORD(out_index+4,-1);
#endif
}
// no sprite information
if(DSP4.out_count == 0)
{
DSP4.out_count = 2;
DSP4_WRITE_WORD(0,0);
}
} while (1);
/////////////////////////////////////
// special cases: plane == 0x0000
// special vehicle case
if(command == 0x90)
{
sprite_type = 1;
// shift bytes
DSP4.parameters[2] = DSP4.parameters[0];
DSP4.parameters[3] = DSP4.parameters[1];
DSP4.parameters[0] = 0;
DSP4.parameters[1] = 0;
goto sprite_found;
}
// special terrain case
else if(command != 0x00 && command != 0xff)
{
sprite_type = 2;
// shift bytes
DSP4.parameters[2] = DSP4.parameters[0];
DSP4.parameters[3] = DSP4.parameters[1];
DSP4.parameters[0] = 0;
DSP4.parameters[1] = 0;
goto sprite_found;
}
} while (1);
terminate:
DSP4.waiting4command = TRUE;
DSP4.out_count=0;
}
#undef PRINT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -