1662 lines
45 KiB
C
Executable File
1662 lines
45 KiB
C
Executable File
/***************************************************************************
|
|
prim.c - description
|
|
-------------------
|
|
begin : Sun Oct 28 2001
|
|
copyright : (C) 2001 by Pete Bernert
|
|
email : BlackDove@addcom.de
|
|
***************************************************************************/
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. See also the license.txt file for *
|
|
* additional informations. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#define _IN_PRIMDRAW
|
|
|
|
#include "externals.h"
|
|
#include "gpu.h"
|
|
#include "draw.h"
|
|
#include "soft.h"
|
|
#include "swap.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// globals
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL bUsingTWin=FALSE;
|
|
TWin_t TWin;
|
|
//unsigned long clutid; // global clut
|
|
unsigned short usMirror=0; // sprite mirror
|
|
int iDither=0;
|
|
int32_t drawX;
|
|
int32_t drawY;
|
|
int32_t drawW;
|
|
int32_t drawH;
|
|
uint32_t dwCfgFixes;
|
|
uint32_t dwActFixes=0;
|
|
uint32_t dwEmuFixes=0;
|
|
int iUseFixes;
|
|
int iUseDither=0;
|
|
BOOL bDoVSyncUpdate=FALSE;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Some ASM color convertion by LEWPY
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef USE_NASM
|
|
|
|
#define BGR24to16 i386_BGR24to16
|
|
extern __inline unsigned short BGR24to16 (uint32_t BGR);
|
|
|
|
#else
|
|
|
|
static __inline unsigned short BGR24to16 (uint32_t BGR)
|
|
{
|
|
return (unsigned short)(((BGR>>3)&0x1f)|((BGR&0xf80000)>>9)|((BGR&0xf800)>>6));
|
|
}
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Update global TP infos
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static __inline void UpdateGlobalTP(unsigned short gdata)
|
|
{
|
|
GlobalTextAddrX = (gdata << 6) & 0x3c0; // texture addr
|
|
|
|
if(iGPUHeight==1024)
|
|
{
|
|
if(dwGPUVersion==2)
|
|
{
|
|
GlobalTextAddrY =((gdata & 0x60 ) << 3);
|
|
GlobalTextIL =(gdata & 0x2000) >> 13;
|
|
GlobalTextABR = (unsigned short)((gdata >> 7) & 0x3);
|
|
GlobalTextTP = (gdata >> 9) & 0x3;
|
|
if(GlobalTextTP==3) GlobalTextTP=2;
|
|
usMirror =0;
|
|
lGPUstatusRet = (lGPUstatusRet & 0xffffe000 ) | (gdata & 0x1fff );
|
|
|
|
// tekken dithering? right now only if dithering is forced by user
|
|
if(iUseDither==2) iDither=2; else iDither=0;
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
GlobalTextAddrY = (unsigned short)(((gdata << 4) & 0x100) | ((gdata >> 2) & 0x200));
|
|
}
|
|
}
|
|
else GlobalTextAddrY = (gdata << 4) & 0x100;
|
|
|
|
GlobalTextTP = (gdata >> 7) & 0x3; // tex mode (4,8,15)
|
|
|
|
if(GlobalTextTP==3) GlobalTextTP=2; // seen in Wild9 :(
|
|
|
|
GlobalTextABR = (gdata >> 5) & 0x3; // blend mode
|
|
|
|
lGPUstatusRet&=~0x000001ff; // Clear the necessary bits
|
|
lGPUstatusRet|=(gdata & 0x01ff); // set the necessary bits
|
|
|
|
switch(iUseDither)
|
|
{
|
|
case 0:
|
|
iDither=0;
|
|
break;
|
|
case 1:
|
|
if(lGPUstatusRet&0x0200) iDither=2;
|
|
else iDither=0;
|
|
break;
|
|
case 2:
|
|
iDither=2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static __inline void SetRenderMode(uint32_t DrawAttributes)
|
|
{
|
|
DrawSemiTrans = (SEMITRANSBIT(DrawAttributes)) ? TRUE : FALSE;
|
|
|
|
if(SHADETEXBIT(DrawAttributes))
|
|
{g_m1=g_m2=g_m3=128;}
|
|
else
|
|
{
|
|
if((dwActFixes&4) && ((DrawAttributes&0x00ffffff)==0))
|
|
DrawAttributes|=0x007f7f7f;
|
|
|
|
g_m1=(short)(DrawAttributes&0xff);
|
|
g_m2=(short)((DrawAttributes>>8)&0xff);
|
|
g_m3=(short)((DrawAttributes>>16)&0xff);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// oki, here are the psx gpu coord rules: poly coords are
|
|
// 11 bit signed values (-1024...1023). If the x or y distance
|
|
// exceeds 1024, the polygon will not be drawn.
|
|
// Since quads are treated as two triangles by the real gpu,
|
|
// this 'discard rule' applies to each of the quad's triangle
|
|
// (so one triangle can be drawn, the other one discarded).
|
|
// Also, y drawing is wrapped at 512 one time,
|
|
// then it will get negative (and therefore not drawn). The
|
|
// 'CheckCoord' funcs are a simple (not comlete!) approach to
|
|
// do things right, I will add a better detection soon... the
|
|
// current approach will be easier to do in hw/accel plugins, imho
|
|
|
|
// 11 bit signed
|
|
#define SIGNSHIFT 21
|
|
#define CHKMAX_X 1024
|
|
#define CHKMAX_Y 512
|
|
|
|
static void AdjustCoord4()
|
|
{
|
|
lx0=(short)(((int)lx0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
lx1=(short)(((int)lx1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
lx2=(short)(((int)lx2<<SIGNSHIFT)>>SIGNSHIFT);
|
|
lx3=(short)(((int)lx3<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly0=(short)(((int)ly0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly1=(short)(((int)ly1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly2=(short)(((int)ly2<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly3=(short)(((int)ly3<<SIGNSHIFT)>>SIGNSHIFT);
|
|
}
|
|
|
|
static void AdjustCoord3()
|
|
{
|
|
lx0=(short)(((int)lx0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
lx1=(short)(((int)lx1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
lx2=(short)(((int)lx2<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly0=(short)(((int)ly0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly1=(short)(((int)ly1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly2=(short)(((int)ly2<<SIGNSHIFT)>>SIGNSHIFT);
|
|
}
|
|
|
|
static void AdjustCoord2()
|
|
{
|
|
lx0=(short)(((int)lx0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
lx1=(short)(((int)lx1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly0=(short)(((int)ly0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly1=(short)(((int)ly1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
}
|
|
|
|
static void AdjustCoord1()
|
|
{
|
|
lx0=(short)(((int)lx0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
ly0=(short)(((int)ly0<<SIGNSHIFT)>>SIGNSHIFT);
|
|
|
|
if(lx0<-512 && PSXDisplay.DrawOffset.x<=-512)
|
|
lx0+=2048;
|
|
|
|
if(ly0<-512 && PSXDisplay.DrawOffset.y<=-512)
|
|
ly0+=2048;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// special checks... nascar, syphon filter 2, mgs
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// xenogears FT4: not removed correctly right now... the tri 0,1,2
|
|
// should get removed, the tri 1,2,3 should stay... pfff
|
|
|
|
// x -466 1023 180 1023
|
|
// y 20 -228 222 -100
|
|
|
|
// 0 __1
|
|
// \ / \
|
|
// 2___3
|
|
|
|
static __inline BOOL CheckCoord4()
|
|
{
|
|
if(lx0<0)
|
|
{
|
|
if(((lx1-lx0)>CHKMAX_X) ||
|
|
((lx2-lx0)>CHKMAX_X))
|
|
{
|
|
if(lx3<0)
|
|
{
|
|
if((lx1-lx3)>CHKMAX_X) return TRUE;
|
|
if((lx2-lx3)>CHKMAX_X) return TRUE;
|
|
}
|
|
}
|
|
}
|
|
if(lx1<0)
|
|
{
|
|
if((lx0-lx1)>CHKMAX_X) return TRUE;
|
|
if((lx2-lx1)>CHKMAX_X) return TRUE;
|
|
if((lx3-lx1)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(lx2<0)
|
|
{
|
|
if((lx0-lx2)>CHKMAX_X) return TRUE;
|
|
if((lx1-lx2)>CHKMAX_X) return TRUE;
|
|
if((lx3-lx2)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(lx3<0)
|
|
{
|
|
if(((lx1-lx3)>CHKMAX_X) ||
|
|
((lx2-lx3)>CHKMAX_X))
|
|
{
|
|
if(lx0<0)
|
|
{
|
|
if((lx1-lx0)>CHKMAX_X) return TRUE;
|
|
if((lx2-lx0)>CHKMAX_X) return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(ly0<0)
|
|
{
|
|
if((ly1-ly0)>CHKMAX_Y) return TRUE;
|
|
if((ly2-ly0)>CHKMAX_Y) return TRUE;
|
|
}
|
|
if(ly1<0)
|
|
{
|
|
if((ly0-ly1)>CHKMAX_Y) return TRUE;
|
|
if((ly2-ly1)>CHKMAX_Y) return TRUE;
|
|
if((ly3-ly1)>CHKMAX_Y) return TRUE;
|
|
}
|
|
if(ly2<0)
|
|
{
|
|
if((ly0-ly2)>CHKMAX_Y) return TRUE;
|
|
if((ly1-ly2)>CHKMAX_Y) return TRUE;
|
|
if((ly3-ly2)>CHKMAX_Y) return TRUE;
|
|
}
|
|
if(ly3<0)
|
|
{
|
|
if((ly1-ly3)>CHKMAX_Y) return TRUE;
|
|
if((ly2-ly3)>CHKMAX_Y) return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static __inline BOOL CheckCoord3()
|
|
{
|
|
if(lx0<0)
|
|
{
|
|
if((lx1-lx0)>CHKMAX_X) return TRUE;
|
|
if((lx2-lx0)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(lx1<0)
|
|
{
|
|
if((lx0-lx1)>CHKMAX_X) return TRUE;
|
|
if((lx2-lx1)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(lx2<0)
|
|
{
|
|
if((lx0-lx2)>CHKMAX_X) return TRUE;
|
|
if((lx1-lx2)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(ly0<0)
|
|
{
|
|
if((ly1-ly0)>CHKMAX_Y) return TRUE;
|
|
if((ly2-ly0)>CHKMAX_Y) return TRUE;
|
|
}
|
|
if(ly1<0)
|
|
{
|
|
if((ly0-ly1)>CHKMAX_Y) return TRUE;
|
|
if((ly2-ly1)>CHKMAX_Y) return TRUE;
|
|
}
|
|
if(ly2<0)
|
|
{
|
|
if((ly0-ly2)>CHKMAX_Y) return TRUE;
|
|
if((ly1-ly2)>CHKMAX_Y) return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static __inline BOOL CheckCoord2()
|
|
{
|
|
if(lx0<0)
|
|
{
|
|
if((lx1-lx0)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(lx1<0)
|
|
{
|
|
if((lx0-lx1)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(ly0<0)
|
|
{
|
|
if((ly1-ly0)>CHKMAX_Y) return TRUE;
|
|
}
|
|
if(ly1<0)
|
|
{
|
|
if((ly0-ly1)>CHKMAX_Y) return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static __inline BOOL CheckCoordL(short slx0,short sly0,short slx1,short sly1)
|
|
{
|
|
if(slx0<0)
|
|
{
|
|
if((slx1-slx0)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(slx1<0)
|
|
{
|
|
if((slx0-slx1)>CHKMAX_X) return TRUE;
|
|
}
|
|
if(sly0<0)
|
|
{
|
|
if((sly1-sly0)>CHKMAX_Y) return TRUE;
|
|
}
|
|
if(sly1<0)
|
|
{
|
|
if((sly0-sly1)>CHKMAX_Y) return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// mask stuff... used in silent hill
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void cmdSTP(unsigned char * baseAddr)
|
|
{
|
|
uint32_t gdata = GETLE32(&((uint32_t*)baseAddr)[0]);
|
|
|
|
lGPUstatusRet&=~0x1800; // Clear the necessary bits
|
|
lGPUstatusRet|=((gdata & 0x03) << 11); // Set the necessary bits
|
|
|
|
if(gdata&1) {sSetMask=0x8000;lSetMask=0x80008000;}
|
|
else {sSetMask=0; lSetMask=0; }
|
|
|
|
if(gdata&2) bCheckMask=TRUE;
|
|
else bCheckMask=FALSE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: Set texture page infos
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void cmdTexturePage(unsigned char * baseAddr)
|
|
{
|
|
uint32_t gdata = GETLE32(&((uint32_t*)baseAddr)[0]);
|
|
|
|
lGPUstatusRet&=~0x000007ff;
|
|
lGPUstatusRet|=(gdata & 0x07ff);
|
|
|
|
usMirror=(unsigned short)(gdata&0x3000);
|
|
|
|
UpdateGlobalTP((unsigned short)gdata);
|
|
GlobalTextREST = (gdata&0x00ffffff)>>9;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: turn on/off texture window
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void cmdTextureWindow(unsigned char *baseAddr)
|
|
{
|
|
uint32_t gdata = GETLE32(&((uint32_t*)baseAddr)[0]);
|
|
|
|
uint32_t YAlign,XAlign;
|
|
|
|
lGPUInfoVals[INFO_TW]=gdata&0xFFFFF;
|
|
|
|
if(gdata & 0x020)
|
|
TWin.Position.y1 = 8; // xxxx1
|
|
else if (gdata & 0x040)
|
|
TWin.Position.y1 = 16; // xxx10
|
|
else if (gdata & 0x080)
|
|
TWin.Position.y1 = 32; // xx100
|
|
else if (gdata & 0x100)
|
|
TWin.Position.y1 = 64; // x1000
|
|
else if (gdata & 0x200)
|
|
TWin.Position.y1 = 128; // 10000
|
|
else
|
|
TWin.Position.y1 = 256; // 00000
|
|
|
|
// Texture window size is determined by the least bit set of the relevant 5 bits
|
|
|
|
if (gdata & 0x001)
|
|
TWin.Position.x1 = 8; // xxxx1
|
|
else if (gdata & 0x002)
|
|
TWin.Position.x1 = 16; // xxx10
|
|
else if (gdata & 0x004)
|
|
TWin.Position.x1 = 32; // xx100
|
|
else if (gdata & 0x008)
|
|
TWin.Position.x1 = 64; // x1000
|
|
else if (gdata & 0x010)
|
|
TWin.Position.x1 = 128; // 10000
|
|
else
|
|
TWin.Position.x1 = 256; // 00000
|
|
|
|
// Re-calculate the bit field, because we can't trust what is passed in the data
|
|
|
|
|
|
YAlign = (uint32_t)(32 - (TWin.Position.y1 >> 3));
|
|
XAlign = (uint32_t)(32 - (TWin.Position.x1 >> 3));
|
|
|
|
// Absolute position of the start of the texture window
|
|
|
|
TWin.Position.y0 = (short)(((gdata >> 15) & YAlign) << 3);
|
|
TWin.Position.x0 = (short)(((gdata >> 10) & XAlign) << 3);
|
|
|
|
if((TWin.Position.x0 == 0 && // tw turned off
|
|
TWin.Position.y0 == 0 &&
|
|
TWin.Position.x1 == 0 &&
|
|
TWin.Position.y1 == 0) ||
|
|
(TWin.Position.x1 == 256 &&
|
|
TWin.Position.y1 == 256))
|
|
{
|
|
bUsingTWin = FALSE; // -> just do it
|
|
}
|
|
else // otherwise
|
|
{
|
|
bUsingTWin = TRUE; // -> tw turned on
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: start of drawing area... primitives will be clipped inside
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void cmdDrawAreaStart(unsigned char * baseAddr)
|
|
{
|
|
uint32_t gdata = GETLE32(&((uint32_t*)baseAddr)[0]);
|
|
|
|
drawX = gdata & 0x3ff; // for soft drawing
|
|
|
|
if(dwGPUVersion==2)
|
|
{
|
|
lGPUInfoVals[INFO_DRAWSTART]=gdata&0x3FFFFF;
|
|
drawY = (gdata>>12)&0x3ff;
|
|
if(drawY>=1024) drawY=1023; // some security
|
|
}
|
|
else
|
|
{
|
|
lGPUInfoVals[INFO_DRAWSTART]=gdata&0xFFFFF;
|
|
drawY = (gdata>>10)&0x3ff;
|
|
if(drawY>=512) drawY=511; // some security
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: end of drawing area... primitives will be clipped inside
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void cmdDrawAreaEnd(unsigned char * baseAddr)
|
|
{
|
|
uint32_t gdata = GETLE32(&((uint32_t*)baseAddr)[0]);
|
|
|
|
drawW = gdata & 0x3ff; // for soft drawing
|
|
|
|
if(dwGPUVersion==2)
|
|
{
|
|
lGPUInfoVals[INFO_DRAWEND]=gdata&0x3FFFFF;
|
|
drawH = (gdata>>12)&0x3ff;
|
|
if(drawH>=1024) drawH=1023; // some security
|
|
}
|
|
else
|
|
{
|
|
lGPUInfoVals[INFO_DRAWEND]=gdata&0xFFFFF;
|
|
drawH = (gdata>>10)&0x3ff;
|
|
if(drawH>=512) drawH=511; // some security
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: draw offset... will be added to prim coords
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void cmdDrawOffset(unsigned char * baseAddr)
|
|
{
|
|
uint32_t gdata = GETLE32(&((uint32_t*)baseAddr)[0]);
|
|
|
|
PSXDisplay.DrawOffset.x = (short)(gdata & 0x7ff);
|
|
|
|
if(dwGPUVersion==2)
|
|
{
|
|
lGPUInfoVals[INFO_DRAWOFF]=gdata&0x7FFFFF;
|
|
PSXDisplay.DrawOffset.y = (short)((gdata>>12) & 0x7ff);
|
|
}
|
|
else
|
|
{
|
|
lGPUInfoVals[INFO_DRAWOFF]=gdata&0x3FFFFF;
|
|
PSXDisplay.DrawOffset.y = (short)((gdata>>11) & 0x7ff);
|
|
}
|
|
|
|
PSXDisplay.DrawOffset.y=(short)(((int)PSXDisplay.DrawOffset.y<<21)>>21);
|
|
PSXDisplay.DrawOffset.x=(short)(((int)PSXDisplay.DrawOffset.x<<21)>>21);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: load image to vram
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primLoadImage(unsigned char * baseAddr)
|
|
{
|
|
unsigned short *sgpuData = ((unsigned short *) baseAddr);
|
|
|
|
VRAMWrite.x = GETLEs16(&sgpuData[2])&0x3ff;
|
|
VRAMWrite.y = GETLEs16(&sgpuData[3])&iGPUHeightMask;
|
|
VRAMWrite.Width = GETLEs16(&sgpuData[4]);
|
|
VRAMWrite.Height = GETLEs16(&sgpuData[5]);
|
|
|
|
DataWriteMode = DR_VRAMTRANSFER;
|
|
|
|
VRAMWrite.ImagePtr = psxVuw + (VRAMWrite.y<<10) + VRAMWrite.x;
|
|
VRAMWrite.RowsRemaining = VRAMWrite.Width;
|
|
VRAMWrite.ColsRemaining = VRAMWrite.Height;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: vram -> psx mem
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primStoreImage(unsigned char * baseAddr)
|
|
{
|
|
unsigned short *sgpuData = ((unsigned short *) baseAddr);
|
|
|
|
VRAMRead.x = GETLEs16(&sgpuData[2])&0x03ff;
|
|
VRAMRead.y = GETLEs16(&sgpuData[3])&iGPUHeightMask;
|
|
VRAMRead.Width = GETLEs16(&sgpuData[4]);
|
|
VRAMRead.Height = GETLEs16(&sgpuData[5]);
|
|
|
|
VRAMRead.ImagePtr = psxVuw + (VRAMRead.y<<10) + VRAMRead.x;
|
|
VRAMRead.RowsRemaining = VRAMRead.Width;
|
|
VRAMRead.ColsRemaining = VRAMRead.Height;
|
|
|
|
DataReadMode = DR_VRAMTRANSFER;
|
|
|
|
lGPUstatusRet |= GPUSTATUS_READYFORVRAM;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: blkfill - NO primitive! Doesn't care about draw areas...
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primBlkFill(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
short sX = GETLEs16(&sgpuData[2]);
|
|
short sY = GETLEs16(&sgpuData[3]);
|
|
short sW = GETLEs16(&sgpuData[4]) & 0x3ff;
|
|
short sH = GETLEs16(&sgpuData[5]) & iGPUHeightMask;
|
|
|
|
sW = (sW+15) & ~15;
|
|
|
|
// Increase H & W if they are one short of full values, because they never can be full values
|
|
if (sH >= 1023) sH=1024;
|
|
if (sW >= 1023) sW=1024;
|
|
|
|
// x and y of end pos
|
|
sW+=sX;
|
|
sH+=sY;
|
|
|
|
FillSoftwareArea(sX, sY, sW, sH, BGR24to16(GETLE32(&gpuData[0])));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: move image vram -> vram
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primMoveImage(unsigned char * baseAddr)
|
|
{
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
short imageY0,imageX0,imageY1,imageX1,imageSX,imageSY,i,j;
|
|
|
|
imageX0 = GETLEs16(&sgpuData[2])&0x03ff;
|
|
imageY0 = GETLEs16(&sgpuData[3])&iGPUHeightMask;
|
|
imageX1 = GETLEs16(&sgpuData[4])&0x03ff;
|
|
imageY1 = GETLEs16(&sgpuData[5])&iGPUHeightMask;
|
|
imageSX = GETLEs16(&sgpuData[6]);
|
|
imageSY = GETLEs16(&sgpuData[7]);
|
|
|
|
if((imageX0 == imageX1) && (imageY0 == imageY1)) return;
|
|
if(imageSX<=0) return;
|
|
if(imageSY<=0) return;
|
|
|
|
// ZN SF2: screwed moves
|
|
//
|
|
// move sgpuData[2],sgpuData[3],sgpuData[4],sgpuData[5],sgpuData[6],sgpuData[7]
|
|
//
|
|
// move 365 182 32723 -21846 17219 15427
|
|
// move 127 160 147 -1 20817 13409
|
|
// move 141 165 16275 -21862 -32126 13442
|
|
// move 161 136 24620 -1 16962 13388
|
|
// move 168 138 32556 -13090 -29556 15500
|
|
//
|
|
// and here's the hack for it:
|
|
|
|
if(iGPUHeight==1024 && GETLEs16(&sgpuData[7])>1024) return;
|
|
|
|
if((imageY0+imageSY)>iGPUHeight ||
|
|
(imageX0+imageSX)>1024 ||
|
|
(imageY1+imageSY)>iGPUHeight ||
|
|
(imageX1+imageSX)>1024)
|
|
{
|
|
int i,j;
|
|
for(j=0;j<imageSY;j++)
|
|
for(i=0;i<imageSX;i++)
|
|
psxVuw [(1024*((imageY1+j)&iGPUHeightMask))+((imageX1+i)&0x3ff)]=
|
|
psxVuw[(1024*((imageY0+j)&iGPUHeightMask))+((imageX0+i)&0x3ff)];
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
if(imageSX&1) // not dword aligned? slower func
|
|
{
|
|
unsigned short *SRCPtr, *DSTPtr;
|
|
unsigned short LineOffset;
|
|
|
|
SRCPtr = psxVuw + (1024*imageY0) + imageX0;
|
|
DSTPtr = psxVuw + (1024*imageY1) + imageX1;
|
|
|
|
LineOffset = 1024 - imageSX;
|
|
|
|
for(j=0;j<imageSY;j++)
|
|
{
|
|
for(i=0;i<imageSX;i++) *DSTPtr++ = *SRCPtr++;
|
|
SRCPtr += LineOffset;
|
|
DSTPtr += LineOffset;
|
|
}
|
|
}
|
|
else // dword aligned
|
|
{
|
|
uint32_t *SRCPtr, *DSTPtr;
|
|
unsigned short LineOffset;
|
|
int dx=imageSX>>1;
|
|
|
|
SRCPtr = (uint32_t *)(psxVuw + (1024*imageY0) + imageX0);
|
|
DSTPtr = (uint32_t *)(psxVuw + (1024*imageY1) + imageX1);
|
|
|
|
LineOffset = 512 - dx;
|
|
|
|
for(j=0;j<imageSY;j++)
|
|
{
|
|
for(i=0;i<dx;i++) *DSTPtr++ = *SRCPtr++;
|
|
SRCPtr += LineOffset;
|
|
DSTPtr += LineOffset;
|
|
}
|
|
}
|
|
|
|
imageSX+=imageX1;
|
|
imageSY+=imageY1;
|
|
|
|
/*
|
|
if(!PSXDisplay.Interlaced) // stupid frame skip stuff
|
|
{
|
|
if(UseFrameSkip &&
|
|
imageX1<PSXDisplay.DisplayEnd.x &&
|
|
imageSX>=PSXDisplay.DisplayPosition.x &&
|
|
imageY1<PSXDisplay.DisplayEnd.y &&
|
|
imageSY>=PSXDisplay.DisplayPosition.y)
|
|
updateDisplay();
|
|
}
|
|
*/
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: draw free-size Tile
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//#define SMALLDEBUG
|
|
//#include <dbgout.h>
|
|
|
|
void primTileS(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t*)baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
short sW = GETLEs16(&sgpuData[4]) & 0x3ff;
|
|
short sH = GETLEs16(&sgpuData[5]) & iGPUHeightMask; // mmm... limit tiles to 0x1ff or height?
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
// x and y of start
|
|
ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y;
|
|
ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y;
|
|
lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x;
|
|
lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x;
|
|
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
if(!(iTileCheat && sH==32 && GETLE32(&gpuData[0])==0x60ffffff)) // special cheat for certain ZiNc games
|
|
FillSoftwareAreaTrans(lx0,ly0,lx2,ly2,
|
|
BGR24to16(GETLE32(&gpuData[0])));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: draw 1 dot Tile (point)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primTile1(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t*)baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
short sH = 1;
|
|
short sW = 1;
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
// x and y of start
|
|
ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y;
|
|
ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y;
|
|
lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x;
|
|
lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x;
|
|
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
FillSoftwareAreaTrans(lx0,ly0,lx2,ly2,
|
|
BGR24to16(GETLE32(&gpuData[0]))); // Takes Start and Offset
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: draw 8 dot Tile (small rect)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primTile8(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t*)baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
short sH = 8;
|
|
short sW = 8;
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
// x and y of start
|
|
ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y;
|
|
ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y;
|
|
lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x;
|
|
lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x;
|
|
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
FillSoftwareAreaTrans(lx0,ly0,lx2,ly2,
|
|
BGR24to16(GETLE32(&gpuData[0]))); // Takes Start and Offset
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: draw 16 dot Tile (medium rect)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primTile16(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t*)baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
short sH = 16;
|
|
short sW = 16;
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
// x and y of start
|
|
ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y;
|
|
ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y;
|
|
lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x;
|
|
lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x;
|
|
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
FillSoftwareAreaTrans(lx0,ly0,lx2,ly2,
|
|
BGR24to16(GETLE32(&gpuData[0]))); // Takes Start and Offset
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: small sprite (textured rect)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primSprt8(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
if(bUsingTWin) DrawSoftwareSpriteTWin(baseAddr,8,8);
|
|
else
|
|
if(usMirror) DrawSoftwareSpriteMirror(baseAddr,8,8);
|
|
else DrawSoftwareSprite(baseAddr,8,8,
|
|
baseAddr[8],
|
|
baseAddr[9]);
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: medium sprite (textured rect)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primSprt16(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
if(bUsingTWin) DrawSoftwareSpriteTWin(baseAddr,16,16);
|
|
else
|
|
if(usMirror) DrawSoftwareSpriteMirror(baseAddr,16,16);
|
|
else DrawSoftwareSprite(baseAddr,16,16,
|
|
baseAddr[8],
|
|
baseAddr[9]);
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: free-size sprite (textured rect)
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// func used on texture coord wrap
|
|
void primSprtSRest(unsigned char * baseAddr,unsigned short type)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
unsigned short sTypeRest=0;
|
|
|
|
short s;
|
|
short sX = GETLEs16(&sgpuData[2]);
|
|
short sY = GETLEs16(&sgpuData[3]);
|
|
short sW = GETLEs16(&sgpuData[6]) & 0x3ff;
|
|
short sH = GETLEs16(&sgpuData[7]) & 0x1ff;
|
|
short tX = baseAddr[8];
|
|
short tY = baseAddr[9];
|
|
|
|
switch(type)
|
|
{
|
|
case 1:
|
|
s=256-baseAddr[8];
|
|
sW-=s;
|
|
sX+=s;
|
|
tX=0;
|
|
break;
|
|
case 2:
|
|
s=256-baseAddr[9];
|
|
sH-=s;
|
|
sY+=s;
|
|
tY=0;
|
|
break;
|
|
case 3:
|
|
s=256-baseAddr[8];
|
|
sW-=s;
|
|
sX+=s;
|
|
tX=0;
|
|
s=256-baseAddr[9];
|
|
sH-=s;
|
|
sY+=s;
|
|
tY=0;
|
|
break;
|
|
case 4:
|
|
s=512-baseAddr[8];
|
|
sW-=s;
|
|
sX+=s;
|
|
tX=0;
|
|
break;
|
|
case 5:
|
|
s=512-baseAddr[9];
|
|
sH-=s;
|
|
sY+=s;
|
|
tY=0;
|
|
break;
|
|
case 6:
|
|
s=512-baseAddr[8];
|
|
sW-=s;
|
|
sX+=s;
|
|
tX=0;
|
|
s=512-baseAddr[9];
|
|
sH-=s;
|
|
sY+=s;
|
|
tY=0;
|
|
break;
|
|
}
|
|
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
if(tX+sW>256) {sW=256-tX;sTypeRest+=1;}
|
|
if(tY+sH>256) {sH=256-tY;sTypeRest+=2;}
|
|
|
|
lx0 = sX;
|
|
ly0 = sY;
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
DrawSoftwareSprite(baseAddr,sW,sH,tX,tY);
|
|
|
|
if(sTypeRest && type<4)
|
|
{
|
|
if(sTypeRest&1 && type==1) primSprtSRest(baseAddr,4);
|
|
if(sTypeRest&2 && type==2) primSprtSRest(baseAddr,5);
|
|
if(sTypeRest==3 && type==3) primSprtSRest(baseAddr,6);
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primSprtS(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
short sW,sH;
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
|
|
if(!(dwActFixes&8)) AdjustCoord1();
|
|
|
|
sW = GETLEs16(&sgpuData[6]) & 0x3ff;
|
|
sH = GETLEs16(&sgpuData[7]) & 0x1ff;
|
|
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
if(bUsingTWin) DrawSoftwareSpriteTWin(baseAddr,sW,sH);
|
|
else
|
|
if(usMirror) DrawSoftwareSpriteMirror(baseAddr,sW,sH);
|
|
else
|
|
{
|
|
unsigned short sTypeRest=0;
|
|
short tX=baseAddr[8];
|
|
short tY=baseAddr[9];
|
|
|
|
if(tX+sW>256) {sW=256-tX;sTypeRest+=1;}
|
|
if(tY+sH>256) {sH=256-tY;sTypeRest+=2;}
|
|
|
|
DrawSoftwareSprite(baseAddr,sW,sH,tX,tY);
|
|
|
|
if(sTypeRest)
|
|
{
|
|
if(sTypeRest&1) primSprtSRest(baseAddr,1);
|
|
if(sTypeRest&2) primSprtSRest(baseAddr,2);
|
|
if(sTypeRest==3) primSprtSRest(baseAddr,3);
|
|
}
|
|
|
|
}
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: flat shaded Poly4
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyF4(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[4]);
|
|
ly1 = GETLEs16(&sgpuData[5]);
|
|
lx2 = GETLEs16(&sgpuData[6]);
|
|
ly2 = GETLEs16(&sgpuData[7]);
|
|
lx3 = GETLEs16(&sgpuData[8]);
|
|
ly3 = GETLEs16(&sgpuData[9]);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord4();
|
|
if(CheckCoord4()) return;
|
|
}
|
|
|
|
offsetPSX4();
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
drawPoly4F(GETLE32(&gpuData[0]));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: smooth shaded Poly4
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyG4(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = (uint32_t *)baseAddr;
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[6]);
|
|
ly1 = GETLEs16(&sgpuData[7]);
|
|
lx2 = GETLEs16(&sgpuData[10]);
|
|
ly2 = GETLEs16(&sgpuData[11]);
|
|
lx3 = GETLEs16(&sgpuData[14]);
|
|
ly3 = GETLEs16(&sgpuData[15]);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord4();
|
|
if(CheckCoord4()) return;
|
|
}
|
|
|
|
offsetPSX4();
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
drawPoly4G(GETLE32(&gpuData[0]), GETLE32(&gpuData[2]),
|
|
GETLE32(&gpuData[4]), GETLE32(&gpuData[6]));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: flat shaded Texture3
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyFT3(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[6]);
|
|
ly1 = GETLEs16(&sgpuData[7]);
|
|
lx2 = GETLEs16(&sgpuData[10]);
|
|
ly2 = GETLEs16(&sgpuData[11]);
|
|
|
|
lLowerpart=GETLE32(&gpuData[4])>>16;
|
|
UpdateGlobalTP((unsigned short)lLowerpart);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord3();
|
|
if(CheckCoord3()) return;
|
|
}
|
|
|
|
offsetPSX3();
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
drawPoly3FT(baseAddr);
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: flat shaded Texture4
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyFT4(unsigned char * baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[6]);
|
|
ly1 = GETLEs16(&sgpuData[7]);
|
|
lx2 = GETLEs16(&sgpuData[10]);
|
|
ly2 = GETLEs16(&sgpuData[11]);
|
|
lx3 = GETLEs16(&sgpuData[14]);
|
|
ly3 = GETLEs16(&sgpuData[15]);
|
|
|
|
lLowerpart=GETLE32(&gpuData[4])>>16;
|
|
UpdateGlobalTP((unsigned short)lLowerpart);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord4();
|
|
if(CheckCoord4()) return;
|
|
}
|
|
|
|
offsetPSX4();
|
|
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
drawPoly4FT(baseAddr);
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: smooth shaded Texture3
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyGT3(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[8]);
|
|
ly1 = GETLEs16(&sgpuData[9]);
|
|
lx2 = GETLEs16(&sgpuData[14]);
|
|
ly2 = GETLEs16(&sgpuData[15]);
|
|
|
|
lLowerpart=GETLE32(&gpuData[5])>>16;
|
|
UpdateGlobalTP((unsigned short)lLowerpart);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord3();
|
|
if(CheckCoord3()) return;
|
|
}
|
|
|
|
offsetPSX3();
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
if(SHADETEXBIT(GETLE32(&gpuData[0])))
|
|
{
|
|
gpuData[0] = (gpuData[0]&HOST2LE32(0xff000000))|HOST2LE32(0x00808080);
|
|
gpuData[3] = (gpuData[3]&HOST2LE32(0xff000000))|HOST2LE32(0x00808080);
|
|
gpuData[6] = (gpuData[6]&HOST2LE32(0xff000000))|HOST2LE32(0x00808080);
|
|
}
|
|
|
|
drawPoly3GT(baseAddr);
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: smooth shaded Poly3
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyG3(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[6]);
|
|
ly1 = GETLEs16(&sgpuData[7]);
|
|
lx2 = GETLEs16(&sgpuData[10]);
|
|
ly2 = GETLEs16(&sgpuData[11]);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord3();
|
|
if(CheckCoord3()) return;
|
|
}
|
|
|
|
offsetPSX3();
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
drawPoly3G(GETLE32(&gpuData[0]), GETLE32(&gpuData[2]), GETLE32(&gpuData[4]));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: smooth shaded Texture4
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyGT4(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[8]);
|
|
ly1 = GETLEs16(&sgpuData[9]);
|
|
lx2 = GETLEs16(&sgpuData[14]);
|
|
ly2 = GETLEs16(&sgpuData[15]);
|
|
lx3 = GETLEs16(&sgpuData[20]);
|
|
ly3 = GETLEs16(&sgpuData[21]);
|
|
|
|
lLowerpart=GETLE32(&gpuData[5])>>16;
|
|
UpdateGlobalTP((unsigned short)lLowerpart);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord4();
|
|
if(CheckCoord4()) return;
|
|
}
|
|
|
|
offsetPSX4();
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
if(SHADETEXBIT(GETLE32(&gpuData[0])))
|
|
{
|
|
gpuData[0] = (gpuData[0]&HOST2LE32(0xff000000))|HOST2LE32(0x00808080);
|
|
gpuData[3] = (gpuData[3]&HOST2LE32(0xff000000))|HOST2LE32(0x00808080);
|
|
gpuData[6] = (gpuData[6]&HOST2LE32(0xff000000))|HOST2LE32(0x00808080);
|
|
gpuData[9] = (gpuData[9]&HOST2LE32(0xff000000))|HOST2LE32(0x00808080);
|
|
}
|
|
|
|
drawPoly4GT(baseAddr);
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: smooth shaded Poly3
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primPolyF3(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[4]);
|
|
ly1 = GETLEs16(&sgpuData[5]);
|
|
lx2 = GETLEs16(&sgpuData[6]);
|
|
ly2 = GETLEs16(&sgpuData[7]);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord3();
|
|
if(CheckCoord3()) return;
|
|
}
|
|
|
|
offsetPSX3();
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
drawPoly3F(GETLE32(&gpuData[0]));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: skipping shaded polylines
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primLineGSkip(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
int iMax=255;
|
|
int i=2;
|
|
|
|
ly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff);
|
|
lx1 = (short)(GETLE32(&gpuData[1]) & 0xffff);
|
|
|
|
while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=4))
|
|
{
|
|
i++;
|
|
ly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff);
|
|
lx1 = (short)(GETLE32(&gpuData[i]) & 0xffff);
|
|
i++;if(i>iMax) break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: shaded polylines
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primLineGEx(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
int iMax=255;
|
|
uint32_t lc0,lc1;
|
|
short slx0,slx1,sly0,sly1;int i=2;BOOL bDraw=TRUE;
|
|
|
|
sly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff);
|
|
slx1 = (short)(GETLE32(&gpuData[1]) & 0xffff);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
slx1=(short)(((int)slx1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
sly1=(short)(((int)sly1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
}
|
|
|
|
lc1 = gpuData[0] & 0xffffff;
|
|
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
|
|
while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=4))
|
|
{
|
|
sly0=sly1; slx0=slx1; lc0=lc1;
|
|
lc1=GETLE32(&gpuData[i]) & 0xffffff;
|
|
|
|
i++;
|
|
|
|
// no check needed on gshaded polyline positions
|
|
// if((gpuData[i] & 0xF000F000) == 0x50005000) break;
|
|
|
|
sly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff);
|
|
slx1 = (short)(GETLE32(&gpuData[i]) & 0xffff);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
slx1=(short)(((int)slx1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
sly1=(short)(((int)sly1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
if(CheckCoordL(slx0,sly0,slx1,sly1)) bDraw=FALSE; else bDraw=TRUE;
|
|
}
|
|
|
|
if ((lx0 != lx1) || (ly0 != ly1))
|
|
{
|
|
ly0=sly0;
|
|
lx0=slx0;
|
|
ly1=sly1;
|
|
lx1=slx1;
|
|
|
|
offsetPSX2();
|
|
if(bDraw) DrawSoftwareLineShade(lc0, lc1);
|
|
}
|
|
i++;
|
|
if(i>iMax) break;
|
|
}
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: shaded polyline2
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primLineG2(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[6]);
|
|
ly1 = GETLEs16(&sgpuData[7]);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord2();
|
|
if(CheckCoord2()) return;
|
|
}
|
|
|
|
if((lx0 == lx1) && (ly0 == ly1)) {lx1++;ly1++;}
|
|
|
|
DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE;
|
|
offsetPSX2();
|
|
DrawSoftwareLineShade(GETLE32(&gpuData[0]),GETLE32(&gpuData[2]));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: skipping flat polylines
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primLineFSkip(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
int i=2,iMax=255;
|
|
|
|
ly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff);
|
|
lx1 = (short)(GETLE32(&gpuData[1]) & 0xffff);
|
|
|
|
while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=3))
|
|
{
|
|
ly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff);
|
|
lx1 = (short)(GETLE32(&gpuData[i]) & 0xffff);
|
|
i++;if(i>iMax) break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: drawing flat polylines
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primLineFEx(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
int iMax;
|
|
short slx0,slx1,sly0,sly1;int i=2;BOOL bDraw=TRUE;
|
|
|
|
iMax=255;
|
|
|
|
sly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff);
|
|
slx1 = (short)(GETLE32(&gpuData[1]) & 0xffff);
|
|
if(!(dwActFixes&8))
|
|
{
|
|
slx1=(short)(((int)slx1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
sly1=(short)(((int)sly1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
}
|
|
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=3))
|
|
{
|
|
sly0 = sly1;slx0=slx1;
|
|
sly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff);
|
|
slx1 = (short)(GETLE32(&gpuData[i]) & 0xffff);
|
|
if(!(dwActFixes&8))
|
|
{
|
|
slx1=(short)(((int)slx1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
sly1=(short)(((int)sly1<<SIGNSHIFT)>>SIGNSHIFT);
|
|
|
|
if(CheckCoordL(slx0,sly0,slx1,sly1)) bDraw=FALSE; else bDraw=TRUE;
|
|
}
|
|
|
|
ly0=sly0;
|
|
lx0=slx0;
|
|
ly1=sly1;
|
|
lx1=slx1;
|
|
|
|
offsetPSX2();
|
|
if(bDraw) DrawSoftwareLineFlat(GETLE32(&gpuData[0]));
|
|
|
|
i++;if(i>iMax) break;
|
|
}
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: drawing flat polyline2
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primLineF2(unsigned char *baseAddr)
|
|
{
|
|
uint32_t *gpuData = ((uint32_t *) baseAddr);
|
|
short *sgpuData = ((short *) baseAddr);
|
|
|
|
lx0 = GETLEs16(&sgpuData[2]);
|
|
ly0 = GETLEs16(&sgpuData[3]);
|
|
lx1 = GETLEs16(&sgpuData[4]);
|
|
ly1 = GETLEs16(&sgpuData[5]);
|
|
|
|
if(!(dwActFixes&8))
|
|
{
|
|
AdjustCoord2();
|
|
if(CheckCoord2()) return;
|
|
}
|
|
|
|
if((lx0 == lx1) && (ly0 == ly1)) {lx1++;ly1++;}
|
|
|
|
offsetPSX2();
|
|
SetRenderMode(GETLE32(&gpuData[0]));
|
|
|
|
DrawSoftwareLineFlat(GETLE32(&gpuData[0]));
|
|
|
|
bDoVSyncUpdate=TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd: well, easiest command... not implemented
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void primNI(unsigned char *bA)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd func ptr table
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void (*primTableJ[256])(unsigned char *) =
|
|
{
|
|
// 00
|
|
primNI,primNI,primBlkFill,primNI,primNI,primNI,primNI,primNI,
|
|
// 08
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 10
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 18
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 20
|
|
primPolyF3,primPolyF3,primPolyF3,primPolyF3,primPolyFT3,primPolyFT3,primPolyFT3,primPolyFT3,
|
|
// 28
|
|
primPolyF4,primPolyF4,primPolyF4,primPolyF4,primPolyFT4,primPolyFT4,primPolyFT4,primPolyFT4,
|
|
// 30
|
|
primPolyG3,primPolyG3,primPolyG3,primPolyG3,primPolyGT3,primPolyGT3,primPolyGT3,primPolyGT3,
|
|
// 38
|
|
primPolyG4,primPolyG4,primPolyG4,primPolyG4,primPolyGT4,primPolyGT4,primPolyGT4,primPolyGT4,
|
|
// 40
|
|
primLineF2,primLineF2,primLineF2,primLineF2,primNI,primNI,primNI,primNI,
|
|
// 48
|
|
primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx,
|
|
// 50
|
|
primLineG2,primLineG2,primLineG2,primLineG2,primNI,primNI,primNI,primNI,
|
|
// 58
|
|
primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx,
|
|
// 60
|
|
primTileS,primTileS,primTileS,primTileS,primSprtS,primSprtS,primSprtS,primSprtS,
|
|
// 68
|
|
primTile1,primTile1,primTile1,primTile1,primNI,primNI,primNI,primNI,
|
|
// 70
|
|
primTile8,primTile8,primTile8,primTile8,primSprt8,primSprt8,primSprt8,primSprt8,
|
|
// 78
|
|
primTile16,primTile16,primTile16,primTile16,primSprt16,primSprt16,primSprt16,primSprt16,
|
|
// 80
|
|
primMoveImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 88
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 90
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 98
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// a0
|
|
primLoadImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// a8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// b0
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// b8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// c0
|
|
primStoreImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// c8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// d0
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// d8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// e0
|
|
primNI,cmdTexturePage,cmdTextureWindow,cmdDrawAreaStart,cmdDrawAreaEnd,cmdDrawOffset,cmdSTP,primNI,
|
|
// e8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// f0
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// f8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// cmd func ptr table for skipping
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
void (*primTableSkip[256])(unsigned char *) =
|
|
{
|
|
// 00
|
|
primNI,primNI,primBlkFill,primNI,primNI,primNI,primNI,primNI,
|
|
// 08
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 10
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 18
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 20
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 28
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 30
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 38
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 40
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 48
|
|
primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,
|
|
// 50
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 58
|
|
primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,
|
|
// 60
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 68
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 70
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 78
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 80
|
|
primMoveImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 88
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 90
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// 98
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// a0
|
|
primLoadImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// a8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// b0
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// b8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// c0
|
|
primStoreImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// c8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// d0
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// d8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// e0
|
|
primNI,cmdTexturePage,cmdTextureWindow,cmdDrawAreaStart,cmdDrawAreaEnd,cmdDrawOffset,cmdSTP,primNI,
|
|
// e8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// f0
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI,
|
|
// f8
|
|
primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI
|
|
};
|