From bb063f4ac553aa44e50d1b1e8d35544613c0426e Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 9 Aug 2026 00:05:03 +0200 Subject: [PATCH] merge initial ps2 rendering support from other project --- premake5.lua | 51 +- src/ps2/ps2.cpp | 3 + src/ps2/ps2device.cpp | 1183 ++++++++++++++++++++++++++++++- src/ps2/ps2file.cpp | 124 ++++ src/ps2/ps2file.h | 7 + src/ps2/ps2immed.cpp | 345 +++++++++ src/ps2/ps2render.cpp | 248 +++++++ src/ps2/ps2types.h | 63 ++ src/ps2/rwgs.h | 53 ++ src/ps2/rwps2.h | 44 ++ src/ps2/rwps2impl.h | 98 +++ src/ps2/vu1/LLclip.vu | 79 +++ src/ps2/vu1/LSclip.vu | 100 +++ src/ps2/vu1/PointCull.vu | 35 + src/ps2/vu1/TLclip.vu | 182 +++++ src/ps2/vu1/TSclip.vu | 187 +++++ src/ps2/vu1/clipline.vu | 230 ++++++ src/ps2/vu1/cliptri.vu | 272 +++++++ src/ps2/vu1/defaultPipe.dsm | 131 ++++ src/ps2/vu1/default_clipproc.vu | 46 ++ src/ps2/vu1/default_proc.vu | 38 + src/ps2/vu1/defines.inc | 65 ++ src/ps2/vu1/im2d.dsm | 123 ++++ src/ps2/vu1/im3d.dsm | 125 ++++ src/ps2/vu1/lighting.vu | 106 +++ 25 files changed, 3904 insertions(+), 34 deletions(-) create mode 100644 src/ps2/ps2file.cpp create mode 100644 src/ps2/ps2file.h create mode 100644 src/ps2/ps2immed.cpp create mode 100644 src/ps2/ps2render.cpp create mode 100644 src/ps2/ps2types.h create mode 100644 src/ps2/rwgs.h create mode 100644 src/ps2/vu1/LLclip.vu create mode 100644 src/ps2/vu1/LSclip.vu create mode 100644 src/ps2/vu1/PointCull.vu create mode 100644 src/ps2/vu1/TLclip.vu create mode 100644 src/ps2/vu1/TSclip.vu create mode 100644 src/ps2/vu1/clipline.vu create mode 100644 src/ps2/vu1/cliptri.vu create mode 100644 src/ps2/vu1/defaultPipe.dsm create mode 100644 src/ps2/vu1/default_clipproc.vu create mode 100644 src/ps2/vu1/default_proc.vu create mode 100644 src/ps2/vu1/defines.inc create mode 100644 src/ps2/vu1/im2d.dsm create mode 100644 src/ps2/vu1/im3d.dsm create mode 100644 src/ps2/vu1/lighting.vu diff --git a/premake5.lua b/premake5.lua index 0cb4afa..bc79a30 100755 --- a/premake5.lua +++ b/premake5.lua @@ -63,8 +63,8 @@ workspace "librw" filter "configurations:Release*" defines { "NDEBUG" } optimize "On" - filter "configurations:ReleaseStatic" - staticruntime("On") +-- filter "configurations:ReleaseStatic" +-- staticruntime("On") filter { "platforms:*null" } defines { "RW_NULL" } @@ -119,6 +119,16 @@ workspace "librw" Libdir = "lib/%{cfg.platform}/%{cfg.buildcfg}" Bindir = "bin/%{cfg.platform}/%{cfg.buildcfg}" +function vucode() + filter "files:**.dsm" + buildmessage 'dvp-as %{file.name}' + buildcommands { + 'cpp -x assembler-with-cpp "%{file.abspath}" | ee-dvp-as -I "%{file.directory}" -o "%{cfg.objdir}/%{file.basename}.o"' + } + buildoutputs { '%{cfg.objdir}/%{file.basename}.o' } + filter {} +end + project "librw" kind "StaticLib" targetname "rw" @@ -128,6 +138,10 @@ project "librw" files { "src/*/*.*" } filter { "platforms:*gl3" } files { "src/gl/glad/*.*" } + filter { "platforms:*ps2" } + vucode() + files { "src/ps2/vu1/*.dsm" } + includedirs { "src/ps2/vu1" } project "dumprwtree" kind "ConsoleApp" @@ -194,15 +208,6 @@ function skeltool(dir) findlibs() end -function vucode() - filter "files:**.dsm" - buildcommands { - 'cpp "%{file.relpath}" | dvp-as -o "%{cfg.objdir}/%{file.basename}.o"' - } - buildoutputs { '%{cfg.objdir}/%{file.basename}.o' } - filter {} -end - project "playground" kind "WindowedApp" characterset ("MBCS") @@ -272,18 +277,18 @@ project "ska2anm" findlibs() removeplatforms { "*gl3", "*d3d9", "*ps2" } -project "ps2test" - kind "ConsoleApp" - targetdir (Bindir) - vucode() - removeplatforms { "*gl3", "*d3d9", "*null" } - targetextension '.elf' - includedirs { "." } - files { "tools/ps2test/*.cpp", - "tools/ps2test/vu/*.dsm", - "tools/ps2test/*.h" } - libdirs { "$(PS2SDK)/ee/lib" } - links { "librw" } +--project "ps2test" +-- kind "ConsoleApp" +-- targetdir (Bindir) +-- vucode() +-- removeplatforms { "*gl3", "*d3d9", "*null" } +-- targetextension '.elf' +-- includedirs { "." } +-- files { "tools/ps2test/*.cpp", +-- "tools/ps2test/vu/*.dsm", +-- "tools/ps2test/*.h" } +-- libdirs { "$(PS2SDK)/ee/lib" } +-- links { "librw" } --project "ps2rastertest" -- kind "ConsoleApp" diff --git a/src/ps2/ps2.cpp b/src/ps2/ps2.cpp index 0f504d6..9d67a13 100644 --- a/src/ps2/ps2.cpp +++ b/src/ps2/ps2.cpp @@ -948,6 +948,9 @@ ObjPipeline::init(void) this->groupPipeline = nil; this->impl.instance = objInstance; this->impl.uninstance = objUninstance; +#ifdef RW_PS2 + this->impl.render = defaultAtomicRender; +#endif } ObjPipeline* diff --git a/src/ps2/ps2device.cpp b/src/ps2/ps2device.cpp index 98f9914..2186b3a 100644 --- a/src/ps2/ps2device.cpp +++ b/src/ps2/ps2device.cpp @@ -8,6 +8,7 @@ #include "../rwbase.h" #include "../rwerror.h" #include "../rwplg.h" +#include "../rwrender.h" #include "../rwpipeline.h" #include "../rwobjects.h" #include "../rwengine.h" @@ -17,30 +18,1190 @@ #include "rwps2plg.h" #include "rwps2impl.h" +#include "rwgs.h" + +#include #define PLUGIN_ID 2 + + +#include +#include + +using namespace rw; + +#define TIMERCONTROL (SCE_PC0_CPU_CYCLE | (SCE_PC_U0|SCE_PC_S0|SCE_PC_K0|SCE_PC_EXL0) | SCE_PC1_DCACHE_MISS | (SCE_PC_U1) | SCE_PC_CTE) + +void +StartTime(void) +{ + DI(); + scePcStart(TIMERCONTROL, 0, 0); + EI(); +} + +int GetTime(void) { return scePcGetCounter0(); } +float GetTimeF(void) { return (float)scePcGetCounter0()/294912.0f; } + +/****** + *** GS + ******/ + +GsCrtState gsCrtState; +GsCtx gsCtx; + +uint32 gsAllocPtr; +uint32 gsStart; +const uint32 gsEnd = (4*1024*1024)/4/64; + +#define SCE_GS_SET_DISPLAY_RAW(dx, dy, magh, magv, dw, dh)\ + ((u_long)((dx)) | \ + ((u_long)((dy)) << 12) | \ + ((u_long)(magh) << 23) | ((u_long)(magv) << 27) | \ + ((u_long)(dw) << 32) | ((u_long)(dh) << 44)) + +void +GsInitDispCtx(GsDispCtx *disp, int width, int height, int psm) +{ + int magh, magv; + int dx, dy; + int dw, dh; + + dx = gsCrtState.mode == SCE_GS_NTSC ? 636 : 656; + dy = gsCrtState.mode == SCE_GS_NTSC ? 25 : 36; + magh = 2560/width - 1; + magv = 0; + dw = 2560-1; + dh = height-1; + + if(gsCrtState.inter == SCE_GS_INTERLACE){ + dy *= 2; + if(gsCrtState.ff == SCE_GS_FRAME) + dh = (dh+1)*2-1; + } + + disp->pmode = SCE_GS_SET_PMODE(0, 1, 1, 1, 1, 0, 0x00); + disp->bgcolor = 0x000000; + disp->dispfb1 = 0; + disp->dispfb2 = SCE_GS_SET_DISPFB(0, width/64, psm, 0, 0); + disp->display1 = 0; + disp->display2 = SCE_GS_SET_DISPLAY_RAW(dx, dy, magh, magv, dw, dh); +} + +void +GsInitDrawCtx(GsDrawCtx *draw, int width, int height, int psm, int zpsm) +{ + MAKE128(draw->gifTag, 0xe, + SCE_GIF_SET_TAG(8, 1, 0, 0, SCE_GIF_PACKED, 1)); + draw->frame1 = SCE_GS_SET_FRAME(0, width/64, psm, 0); + draw->ad_frame1 = SCE_GS_FRAME_1; + draw->frame2 = draw->frame1; + draw->ad_frame2 = SCE_GS_FRAME_2; + draw->zbuf1 = SCE_GS_SET_ZBUF(0, zpsm, 0); + draw->ad_zbuf1 = SCE_GS_ZBUF_1; + draw->zbuf2 = draw->zbuf1; + draw->ad_zbuf2 = SCE_GS_ZBUF_2; + draw->xyoffset1 = SCE_GS_SET_XYOFFSET((2048-width/2)<<4, (2048-height/2)<<4); + draw->ad_xyoffset1 = SCE_GS_XYOFFSET_1; + draw->xyoffset2 = draw->xyoffset1; + draw->ad_xyoffset2 = SCE_GS_XYOFFSET_2; + draw->scissor1 = SCE_GS_SET_SCISSOR(0, width-1, 0, height-1); + draw->ad_scissor1 = SCE_GS_SCISSOR_1; + draw->scissor2 = draw->scissor1; + draw->ad_scissor2 = SCE_GS_SCISSOR_2; +} + +int psmsizemap[64] = { + 4, // PSMCT32 + 4, // PSMCT24 + 2, // PSMCT16 + 0, 0, 0, 0, 0, 0, 0, + 2, // PSMCT16S + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, // PSMZ32 + 4, // PSMZ24 + 2, // PSMZ16 + 2, // PSMZ16S + 0, 0, 0, 0, 0 +}; + +void +GsInitCtx(GsCtx *ctx, int width, int height, int psm, int zpsm) +{ + uint32 fbsz, zbsz; + uint32 fbp, zbp; + fbsz = (width*height*psmsizemap[psm] + 2047)/2048; + zbsz = (width*height*psmsizemap[0x30|zpsm] + 2047)/2048; + gsAllocPtr = (2*fbsz + zbsz)*2048; + fbp = fbsz; + zbp = fbsz*2; + + // word addresses + fbp >>= 2; + zbp >>= 2; + + // display buffers + GsInitDispCtx(&ctx->disp[0], width, height, psm); + ctx->disp[1] = ctx->disp[0]; + ctx->disp[1].dispfb2 |= fbp; + + // draw buffers + GsInitDrawCtx(&ctx->draw[0], width, height, psm, zpsm); + ctx->draw[0].zbuf1 |= zbp; + ctx->draw[0].zbuf2 |= zbp; + ctx->draw[1] = ctx->draw[0]; + ctx->draw[1].frame1 |= fbp; + ctx->draw[1].frame2 |= fbp; +} + +void +GsSetDisp(GsDispCtx *disp) +{ + *GS_PMODE = disp->pmode; + *GS_DISPFB1 = disp->dispfb1; + *GS_DISPLAY1 = disp->display1; + *GS_DISPFB2 = disp->dispfb2; + *GS_DISPLAY2 = disp->display2; + *GS_BGCOLOR = disp->bgcolor; +} + +void +GsSetDraw(GsDrawCtx *draw) +{ + using namespace rw::ps2; + vifPacket[vifPacksz].q_u128 = 0; + vifPacket[vifPacksz].q_u32[0] = DMAref + 9; + vifPacket[vifPacksz].q_u32[1] = (uint32)draw; + // VIF DIRECT + vifPacket[vifPacksz].q_u32[3] = VIFdirect + 9; + vifPacksz++; +} + namespace rw { namespace ps2 { +/******* + *** DMA + *******/ + +// texture upload method +int path2Textures = 0; +int synchTextures = 0; +int gateTextures = 1; + +int finishCycle; +sceDmaChan *dmaGif; +sceDmaChan *dmaVif; + +uint32 VIFgate[] __attribute__((aligned (128))) = { + // we FLUSHA before this in the DMAref tag + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFflush, VIFnop, VIFnop, VIFunmskpath3, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFnop, VIFnop, VIFnop, VIFnop, + VIFmskpath3, VIFnop, VIFnop, VIFnop, + ////// for synchronous upload + VIFflush, VIFflusha, VIFflush, VIFflusha, +}; + +uint32 VIFmask[] __attribute__((aligned (128))) = { + DMAend, 0, VIFmskpath3, VIFnop +}; +uint32 VIFunmask[] __attribute__((aligned (128))) = { + DMAend, 0, VIFunmskpath3, VIFnop +}; + +void +dumpmatrix(rw::RawMatrix *m) +{ + printf("%f %f %f %f\n", m->right.x, m->up.x, m->at.x, m->pos.x); + printf("%f %f %f %f\n", m->right.y, m->up.y, m->at.y, m->pos.y); + printf("%f %f %f %f\n", m->right.z, m->up.z, m->at.z, m->pos.z); + printf("%f %f %f %f\n", m->rightw, m->upw, m->atw, m->posw); +} + +uint32 gifPacksz, gifBufSize; +uint32 vifPacksz, vifBufSize; +char *gifBufBase, *vifBufBase; +QWord *gifPacket, *vifPacket; +QWord *gifPacketEnd, *vifPacketEnd; +QWord *texPtrBuf[4 * 1024]; +QWord **texListBuild, **texListDraw; +int numTexBuild, numTexDraw; +QWord *texMarkSlot; + +// debug +int marks[1024]; +int codes[1024]; +int stats[1024]; +int numVIFinterrupts; + +void +dmaFlip(int i) +{ + i &= 1; + gifPacksz = 0; + vifPacksz = 0; + gifPacket = (QWord*)(gifBufBase + i*gifBufSize); + gifPacket = (QWord*)((uint32)gifPacket | 0x30000000); + gifPacketEnd = (QWord*)((char*)gifPacket + gifBufSize); + vifPacket = (QWord*)(vifBufBase + i*vifBufSize); + vifPacket = (QWord*)((uint32)vifPacket | 0x30000000); + vifPacketEnd = (QWord*)((char*)vifPacket + vifBufSize); + texMarkSlot = nil; +} + +void +dmaInit(void) +{ + /* 2*512kb each */ + gifBufSize = 512*1024; + vifBufSize = 512*1024; + // TODO: better alignment + gifBufBase = (char*)malloc(2*gifBufSize); + vifBufBase = (char*)malloc(2*vifBufSize); + assert(((uint32)gifBufBase & 0xF) == 0); + assert(((uint32)vifBufBase & 0xF) == 0); + dmaFlip(0); + texListBuild = texPtrBuf; + texListDraw = &texPtrBuf[sizeof(texPtrBuf)/2]; +} + +void +dmaKick(void) +{ + QWord **t; + uint128 tmp; + MAKE128(tmp, 0x0, DMAend); + + numVIFinterrupts = 0; + gifPacket[gifPacksz++].q_u128 = tmp; + if(!synchTextures && gateTextures) + vifPacket[vifPacksz++].q_u128 = *(uint128*)VIFunmask; + else + vifPacket[vifPacksz++].q_u128 = tmp; + + assert(&vifPacket[vifPacksz] < vifPacketEnd); + assert(&gifPacket[gifPacksz] < gifPacketEnd); + + numTexDraw = numTexBuild; + numTexBuild = 0; + t = texListDraw; texListDraw = texListBuild; texListBuild = t; + + FlushCache(0); + if(!synchTextures && gateTextures){ + sceDmaSend(dmaVif, VIFmask); + if(gifPacksz > 1) + sceDmaSend(dmaGif, (void*)((uint32)gifPacket & ~0xF0000000)); + } + + if(vifPacksz > 1) + sceDmaSend(dmaVif, (void*)((uint32)vifPacket & ~0xF0000000)); +} + +int +gsHandler(int id) +{ + if(*GS_CSR & GS_CSR_FINISH_M){ + finishCycle = GetTime(); + *GS_CSR = GS_CSR_FINISH_M; + } + ExitHandler(); + return 0; +} + +int +dmacVif1Handler(int id) +{ + if(id == DMAC_VIF1){ + /* If tag interrupt, have to restart */ + if(dmaVif->chcr.TAG & 0x8000) + dmaVif->chcr.STR = 1; + } + ExitHandler(); + return 0; +} + +int +vif1Handler(int id) +{ + assert(!synchTextures && !gateTextures); + uint32 mark = *VIF1_MARK; +// uint32 code = *VIF1_CODE; +// uint32 stat = *VIF1_STAT; +// marks[numVIFinterrupts] = mark; +// codes[numVIFinterrupts] = code; +// stats[numVIFinterrupts] = stat; +// numVIFinterrupts++; + + assert(mark < numTexDraw); + sceDmaSend(dmaGif, texListDraw[mark]); + /* wait for GIF chain to start before restarting VIF1 */ + while(dmaGif->chcr.STR == 0); + + /* restart VIF1 */ + *VIF1_FBRST = 8; + + ExitHandler(); + return 0; +} + + +/****** + *** RW + ******/ + +uint32 *currentVUCode; + +/* +It would be nice to be able to test against RW's microcode. +need to set up VU qwords like this: + + 0x3F0 vuSDmat0 combined matrix; w row = z row + 0x3F1 vuSDmat1 combined matrix + 0x3F2 vuSDmat2 combined matrix + 0x3F3 vuSDmat3 combined matrix + 0x3F4 vuSDnearClip xyzw: camera near plane vu1DataNearClip + 0x3F5 vuSDfarClip xyzw: camera far plane vu1DataFarClip + 0x3F6 vuSDxMaxyMax ?, ?, -255/(fogEnd-fogStart), fogEnd xMaxYMax128 + 0x3F7 vuSDcamWcamHzScale raster width, raster height, zScale, 0 vu1DataXYZScale + 0x3F8 vuSDoffXoffYzShift 0, 0, zShift, 0 vu1DataXYZShift + 0x3F9 vuSDrealOffset xoff, yoff, 0, 0 vu1DataOffset3D + 0x3FA vuSDgifTag gifTag128 + 0x3FB vuSDcolScale material color (scaled by 128/255 when textured) + 0x3FC vuSDsurfProps surface properties + 0x3FD vuSDClipvec1 cull: 2047.9374-screenWidth/2, 1/x, zScaleClip, far plane skyClipVect1 + clip: screenWidth/2 + 5, 1/x, zScaleClip, far plane skyCClipVect1 + 0x3FE vuSDClipvec2 cull: 2047.9374-screenHeight/2, 1/x, zShiftClip, near plane skyClipVect2 + clip: screenHeight/2 + 5, 1/x, zShiftClip, near plane skyCClipVect2 + 0x3FF vuSDVUSwitch code path switch, render system, ?, (backface cull) + +xoff = fb->width/2 + fb->offsetX - par->width/2 + 2048 +yoff = fb->height/2 + fb->offsetY - par->height/2 + 2048 + +persp zScaleClip: -2*far*near/(far-near) +persp zShiftClip: (far+near)/(far-near) +paral zScaleClip: 2/(far-near) +paral zShiftClip: -(far+near)/(far-near) + */ + +VuConst vuConst; +Raster *cachedTex; +RwStateCache rwStateCache; + +float fogFarPlane; // not sure if we want to keep this +float zScaleScreen; +float zShiftScreen; +float fogScale; +float fogShift; + +int32 doClipping = 1; +int32 doModulate2; + +#define COLSCALE (128.0f/255.0f) // TODO: check rounding on VU1 of this + +QWord colorNoScale; +QWord colorTexScale; + +bool flushTex; +struct GSregs { + uint64 alpha_1; + uint64 test_1; + uint64 prmode; + uint64 fogcol; + uint64 tex0_1; + uint64 tex1_1; + uint64 clamp_1; +} gsRegs, prevGsRegs; + +int rw2gsPrim[] = { + 0, // PRIMTYPENONE + 1, // PRIMTYPELINELIST + 2, // PRIMTYPEPOLYLINE + 3, // PRIMTYPETRILIST + 4, // PRIMTYPETRISTRIP + 5, // PRIMTYPETRIFAN + 0, // PRIMTYPEPOINTLIST +}; + +int primSize[] = { + 0, // PRIMTYPENONE + 2, // PRIMTYPELINELIST + 2, // PRIMTYPEPOLYLINE + 3, // PRIMTYPETRILIST + 3, // PRIMTYPETRISTRIP + 3, // PRIMTYPETRIFAN + 1, // PRIMTYPEPOINTLIST +}; + +int primRepeat[] = { + 0, // PRIMTYPENONE + 0, // PRIMTYPELINELIST + 1, // PRIMTYPEPOLYLINE + 0, // PRIMTYPETRILIST + 2, // PRIMTYPETRISTRIP + 2, // PRIMTYPETRIFAN special case + 0, // PRIMTYPEPOINTLIST +}; + +void +clearCamera(Camera *cam, RGBA *col, uint32 mode) +{ + uint128 tmp; + const int nstrips = SCREEN_WIDTH/32; + + // TODO: only clear subraster + MAKEQ(tmp, VIFdirect + 6 + nstrips*2, VIFnop, 0, DMAcnt + 6 + nstrips*2); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, 0xe, SCE_GIF_SET_TAG(5 + nstrips*2, 1, 1,SCE_GS_PRIM_SPRITE, SCE_GIF_PACKED, 1)); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_TEST_1, SCE_GS_SET_TEST(0, 0, 0, 0, 0, 0, 1, 1)); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_PRMODE, SCE_GS_SET_PRMODE(0, 0, 0, 0, 0, 0, 0, 0)); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_RGBAQ, SCE_GS_SET_RGBAQ(col->red, col->green, col->blue, 0, 0)); + vifPacket[vifPacksz++].q_u128 = tmp; + + for(int i = 0; i < nstrips; i++){ + int x = 2048 - SCREEN_WIDTH/2; + int y = 2048 - SCREEN_HEIGHT/2; + MAKE128(tmp, SCE_GS_XYZ2, SCE_GS_SET_XYZ((x+i*32)<<4, y<<4, 0)); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_XYZ2, SCE_GS_SET_XYZ((x+(i+1)*32)<<4, (y+SCREEN_HEIGHT)<<4, 0)); + vifPacket[vifPacksz++].q_u128 = tmp; + } + + MAKE128(tmp, SCE_GS_TEST_1, prevGsRegs.test_1); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_PRMODE, prevGsRegs.prmode); + vifPacket[vifPacksz++].q_u128 = tmp; +} + +void +InitGSregs(void) +{ + uint128 tmp; + + int nregs = 3; + MAKEQ(tmp, VIFdirect + nregs+1, VIFnop, 0, DMAcnt + nregs+1); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, 0xe, SCE_GIF_SET_TAG(nregs, 1, 0,0, SCE_GIF_PACKED, 1)); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_PRMODECONT, 0); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_PRIM, gsRegs.prmode); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_PRMODE, gsRegs.prmode); + vifPacket[vifPacksz++].q_u128 = tmp; +} + +// cannot blend with color at all +int blendMap[] = { + -1, // invalid + 0, // BLENDZERO + 1, // BLENDONE + -1, // BLENDSRCCOLOR + -1, // BLENDINVSRCCOLOR + 2, // BLENDSRCALPHA + 3, // BLENDINVSRCALPHA + 4, // BLENDDESTALPHA + 5, // BLENDINVDESTALPHA + -1, // BLENDDESTCOLOR + -1, // BLENDINVDESTCOLOR + -1 // BLENDSRCALPHASAT +}; +int64 blendTable[6][6] = { // [src][dst] + 0x000000008A, 0x000000004A, 0x0000000089, 0x0000000046, 0x0000000099, 0x0000000056, + 0x000000000A, 0x8000000029, 0x0000000009, -1, 0x0000000019, -1, + 0x0000000088, 0x0000000048, -1, 0x0000000044, -1, -1, + 0x0000000002, -1, 0x0000000001, -1, -1, -1, + 0x0000000098, 0x0000000058, -1, -1, -1, 0x0000000054, + 0x0000000012, -1, -1, -1, 0x0000000011, -1, +}; + +void +setAlphaBlend(int32 src, int32 dst) +{ + int64 alpha; + src = blendMap[src]; + dst = blendMap[dst]; + if(src < 0 || dst < 0) + return; + alpha = blendTable[src][dst]; + if(alpha < 0) + return; + gsRegs.alpha_1 = alpha; +} + +void +setRenderState(int32 state, void *pvalue) +{ + uint32 value = (uint32)pvalue; + switch(state){ + case TEXTURERASTER: + rwStateCache.raster = (Raster*)pvalue; + if(rwStateCache.raster && + ((rwStateCache.raster->format & 0xF00) == Raster::C1555 || + (rwStateCache.raster->format & 0xF00) == Raster::C8888)) + rwStateCache.textureAlpha = 1; + else + rwStateCache.textureAlpha = 0; + goto setblend; + case TEXTUREADDRESS: + rwStateCache.addressU = value; + rwStateCache.addressV = value; + break; + case TEXTUREADDRESSU: + rwStateCache.addressU = value; + break; + case TEXTUREADDRESSV: + rwStateCache.addressV = value; + break; + case TEXTUREFILTER: + rwStateCache.filterMode = value; + break; + + case VERTEXALPHA: + rwStateCache.vertexAlpha = value; + setblend: + if(rwStateCache.vertexAlpha || rwStateCache.textureAlpha) + gsRegs.prmode |= 0x40; + else + gsRegs.prmode &= ~0x40; + break; + case SRCBLEND: + rwStateCache.srcblend = value; + setAlphaBlend(rwStateCache.srcblend, rwStateCache.destblend); + break; + case DESTBLEND: + rwStateCache.destblend = value; + setAlphaBlend(rwStateCache.srcblend, rwStateCache.destblend); + break; + + case ZTESTENABLE: + rwStateCache.ztest = value; + if(rwStateCache.ztest) + gsRegs.test_1 = (gsRegs.test_1 & ~0x60000) | 0x40000; + else + gsRegs.test_1 = (gsRegs.test_1 & ~0x60000) | 0x20000; + break; + case ZWRITEENABLE: + // TODO + break; + + case FOGENABLE: + rwStateCache.fogEnable = value; + if(rwStateCache.fogEnable) + gsRegs.prmode |= 0x20; + else + gsRegs.prmode &= ~0x20; + break; + case FOGCOLOR: + gsRegs.fogcol = value&0xFFFFFF; + break; + + case ALPHATESTFUNC: + break; + case ALPHATESTREF: + break; + } +} + +void* +getRenderState(int32 state) +{ +} + +// in librw +void printTEX0(uint64 tex0); +void printTEX1(uint64 tex1); +void calcTEX1(Raster *raster, uint64 *tex1, int32 filter); + +void +printGIFtag(uint128 tag) +{ + QWord q; + uint64 x; + q.q_u128 = tag; + x = q.q_u64[0]; + + uint32 nloop = x & 0x7FFF; x >>= 15; + uint32 eop = x & 0x1; x >>= 1; + x >>= 30; + uint32 pre = x & 0x1; x >>= 1; + uint32 prim = x & 0x7FF; x >>= 11; + uint32 flg = x & 0x3; x >>= 2; + uint32 nreg = x & 0xF; x >>= 4; + printf("%016lX %016lX ", q.q_u64[0], q.q_u64[1]); + printf("NLOOP:%4X EOP:%X PRE:%X PRIM:%3X FLG:%X NREG:%X\n", + nloop, eop, pre, prim, flg, nreg); +} + +void +printBITBLTBUF(uint64 bitblt) +{ + printf("%016lX ", bitblt); + uint32 sbp = bitblt & 0x3FFF; bitblt >>= 14; + bitblt >>= 2; + uint32 sbw = bitblt & 0x3F; bitblt >>= 6; + bitblt >>= 2; + uint32 spsm = bitblt & 0x3F; bitblt >>= 6; + bitblt >>= 2; + uint32 dbp = bitblt & 0x3FFF; bitblt >>= 14; + bitblt >>= 2; + uint32 dbw = bitblt & 0x3F; bitblt >>= 6; + bitblt >>= 2; + uint32 dpsm = bitblt & 0x3F; bitblt >>= 6; + bitblt >>= 2; + printf("SBP:%4X SBW:%2X SPSM:%2X DBP:%4X DBW:%2X DPSM:%2X\n", + sbp, sbw, spsm, dbp, dbw, dpsm); +} + +void +uploadRaster(Raster *raster) +{ + QWord q; + uint128 tmp; + int i; + + if(cachedTex == raster) + return; + cachedTex = raster; + if(raster == nil) + return; + + Ps2Raster *ext = GETPS2RASTEREXT(raster); + Ps2Raster::PixelPtr *pp = (Ps2Raster::PixelPtr*)ext->data; + uint128 *xferchain = (uint128*)(ext->data + 0x10); + + /* poor man's texture cache */ + static int pingpong; + uint32 sz = (gsEnd - gsStart)/2; + uint32 base = gsStart + pingpong*sz; + pingpong = !pingpong; + assert(sz*64 >= ext->totalSize); + + if(path2Textures){ + // This is really stupid right now: + // - no cache + // - PATH2 + for(i = 0; i < pp->numTransfers; i++){ + // add packets to upload texture levels & palette + // DMAcnt + vifPacket[vifPacksz++].q_u128 = *xferchain++; + // GIFTAG + vifPacket[vifPacksz++].q_u128 = *xferchain++; + // BITBLTBUF + q.q_u128 = *xferchain++; + q.q_u32[1] += base; + vifPacket[vifPacksz++] = q; + // DMAref for actual GIF upload + vifPacket[vifPacksz++].q_u128 = *xferchain++; + } + + // End the primitive -- a bit ugly :/ + MAKEQ(tmp, VIFdirect + 1, VIFnop, 0, DMAcnt + 1); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, 0xe, SCE_GIF_SET_TAG(0, 1, 0,0, SCE_GIF_PACKED, 0)); + vifPacket[vifPacksz++].q_u128 = tmp; + }else{ + if(synchTextures){ + MAKEQ(tmp, IntFlg|VIFnop, VIFmark | numTexBuild, 0, DMAcnt+1); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKEQ(tmp, VIFflusha, VIFflusha, VIFflusha, VIFflusha); + vifPacket[vifPacksz++].q_u128 = tmp; + }else if(gateTextures){ + if(texMarkSlot == nil){ + /* Start chain of image uploads - first one is synchronous */ + MAKEQ(tmp, VIFflusha, VIFflush, VIFgate, DMAref + sizeof(VIFgate)/16); + vifPacket[vifPacksz++].q_u128 = tmp; + }else{ + /* Start image we need now at earlier point in chain */ + MAKEQ(tmp, VIFflusha, VIFflush, VIFgate, DMAref + sizeof(VIFgate)/16 - 1); + texMarkSlot->q_u128 = tmp; + /* and wait here for it to be transferred */ + MAKEQ(tmp, VIFflusha, VIFflusha, 0, DMAcnt); + vifPacket[vifPacksz++].q_u128 = tmp; + } + /* Will start next transfer here */ + texMarkSlot = &vifPacket[vifPacksz]; + MAKEQ(tmp, VIFnop, VIFnop, 0, DMAcnt); + vifPacket[vifPacksz++].q_u128 = tmp; + }else{ + if(texMarkSlot == nil){ + /* Start chain of image uploads - first one is synchronous */ + MAKEQ(tmp, VIFnop, VIFflusha, 0, DMAcnt+2); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKEQ(tmp, VIFnop, VIFflusha, IntFlg|VIFnop, VIFmark | numTexBuild); + vifPacket[vifPacksz++].q_u128 = tmp; + }else{ + /* Start image we need now at earlier point in chain */ + MAKEQ(tmp, VIFnop, VIFnop, IntFlg|VIFnop, VIFmark | numTexBuild); + texMarkSlot->q_u128 = tmp; + /* and wait here for it to be transferred */ + MAKEQ(tmp, VIFnop, VIFflusha, 0, DMAcnt+1); + vifPacket[vifPacksz++].q_u128 = tmp; + } + /* Will start next transfer here */ + texMarkSlot = &vifPacket[vifPacksz]; + MAKEQ(tmp, VIFnop, VIFnop, VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + } + + texListBuild[numTexBuild++] = gifPacket + gifPacksz; + for(i = 0; i < pp->numTransfers; i++){ + // add packets to upload texture levels & palette + // DMAcnt + gifPacket[gifPacksz++].q_u128 = *xferchain++; + // GIFTAG + gifPacket[gifPacksz++].q_u128 = *xferchain++; + // BITBLTBUF + q.q_u128 = *xferchain++; + q.q_u32[1] += base; + gifPacket[gifPacksz++] = q; + // DMAref for actual GIF upload + gifPacket[gifPacksz++].q_u128 = *xferchain++; + } + + // End the primitive -- a bit ugly :/ + if(!synchTextures && gateTextures) + MAKEQ(tmp, VIFdirect + 1, VIFnop, 0, DMAcnt + 1); + else + MAKEQ(tmp, VIFdirect + 1, VIFnop, 0, DMAend + 1); + gifPacket[gifPacksz++].q_u128 = tmp; + MAKE128(tmp, 0xe, SCE_GIF_SET_TAG(0, 1, 0,0, SCE_GIF_PACKED, 0)); + gifPacket[gifPacksz++].q_u128 = tmp; + } + + ext->tex0 = (ext->tex0 & ~0x3FFFUL) | base; + if(ext->paletteBase) + ext->tex0 = (ext->tex0 & ~(0x3FFFUL<<37)) | (uint64)(base+ext->paletteBase)<<37; +} + +void +setTexture(Raster *raster, uint32 addressU, uint32 addressV, uint32 filterMode) +{ + uint64 tex1; + if(raster == nil){ + gsRegs.prmode &= ~0x10; + return; + } + gsRegs.prmode |= 0x10; + Ps2Raster *ext = GETPS2RASTEREXT(raster); + calcTEX1(raster, &tex1, filterMode); + gsRegs.tex0_1 = ext->tex0; + gsRegs.tex1_1 = tex1; + gsRegs.clamp_1 = tex1; + flushTex = true; + if(addressU == Texture::WRAP || addressU == Texture::MIRROR) + gsRegs.clamp_1 &= ~0x3UL; + else + gsRegs.clamp_1 = gsRegs.clamp_1&~0x3UL | 1; + if(addressV == Texture::WRAP || addressV == Texture::MIRROR) + gsRegs.clamp_1 &= ~0xCUL; + else + gsRegs.clamp_1 = gsRegs.clamp_1&~0xCUL | 4; +} + +void +flushGSRegs(void) +{ + uint128 tmp; + uint128 *p; + + // DMAcnt and GIFtag + p = &vifPacket[vifPacksz].q_u128; + vifPacksz += 2; + + uint32 oldPacksz = vifPacksz; + if(prevGsRegs.alpha_1 != gsRegs.alpha_1){ + prevGsRegs.alpha_1 = gsRegs.alpha_1; + MAKE128(tmp, SCE_GS_ALPHA_1, gsRegs.alpha_1); + vifPacket[vifPacksz++].q_u128 = tmp; + } + if(prevGsRegs.prmode != gsRegs.prmode){ + prevGsRegs.prmode = gsRegs.prmode; + MAKE128(tmp, SCE_GS_PRMODE, gsRegs.prmode); + vifPacket[vifPacksz++].q_u128 = tmp; + } + if(prevGsRegs.fogcol != gsRegs.fogcol){ + prevGsRegs.fogcol = gsRegs.fogcol; + MAKE128(tmp, SCE_GS_FOGCOL, gsRegs.fogcol); + vifPacket[vifPacksz++].q_u128 = tmp; + } + + /* A new texture needs to write both TEXFLUSH *and* TEX0 for some reason. + * different pixels with the same TEX0 can still cause issues. + * probably because of CLUT buffer */ + if(flushTex){ + flushTex = false; + prevGsRegs.tex0_1 = gsRegs.tex0_1; + MAKE128(tmp, SCE_GS_TEXFLUSH, 0); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, SCE_GS_TEX0_1, gsRegs.tex0_1); + vifPacket[vifPacksz++].q_u128 = tmp; + } + if(prevGsRegs.tex1_1 != gsRegs.tex1_1){ + prevGsRegs.tex1_1 = gsRegs.tex1_1; + MAKE128(tmp, SCE_GS_TEX1_1, gsRegs.tex1_1); + vifPacket[vifPacksz++].q_u128 = tmp; + } + if(prevGsRegs.clamp_1 != gsRegs.clamp_1){ + prevGsRegs.clamp_1 = gsRegs.clamp_1; + MAKE128(tmp, SCE_GS_CLAMP_1, gsRegs.clamp_1); + vifPacket[vifPacksz++].q_u128 = tmp; + } + if(prevGsRegs.test_1 != gsRegs.test_1){ + prevGsRegs.test_1 = gsRegs.test_1; + MAKE128(tmp, SCE_GS_TEST_1, gsRegs.test_1); + vifPacket[vifPacksz++].q_u128 = tmp; + } + + // nothing to add... + int nregs = vifPacksz - oldPacksz; + if(nregs == 0){ + vifPacksz -= 2; + return; + } + + MAKEQ(tmp, VIFdirect + nregs+1, VIFflush, 0, DMAcnt + nregs+1); + *p++ = tmp; + MAKE128(tmp, 0xe, SCE_GIF_SET_TAG(nregs, 1, 0,0, SCE_GIF_PACKED, 1)); + *p++ = tmp; +} + +void +beginUpdate(Camera *cam) +{ + engine->currentCamera = cam; + + // Screw it, we're building our own matrices + float view[16], proj[16]; + // View Matrix + Matrix inv; + Matrix::invert(&inv, cam->getFrame()->getLTM()); + // Since we're looking into positive Z, + // flip X to ge a left handed view space. + view[0] = -inv.right.x; + view[1] = inv.right.y; + view[2] = inv.right.z; + view[3] = 0.0f; + view[4] = -inv.up.x; + view[5] = inv.up.y; + view[6] = inv.up.z; + view[7] = 0.0f; + view[8] = -inv.at.x; + view[9] = inv.at.y; + view[10] = inv.at.z; + view[11] = 0.0f; + view[12] = -inv.pos.x; + view[13] = inv.pos.y; + view[14] = inv.pos.z; + view[15] = 1.0f; + memcpy(&cam->devView, &view, sizeof(RawMatrix)); + + // Projection Matrix + float32 invwx = 1.0f/cam->viewWindow.x; + float32 invwy = 1.0f/cam->viewWindow.y; + float32 invz = 1.0f/(cam->farPlane-cam->nearPlane); + + proj[0] = invwx; + proj[1] = 0.0f; + proj[2] = 0.0f; + proj[3] = 0.0f; + + proj[4] = 0.0f; + proj[5] = invwy; + proj[6] = 0.0f; + proj[7] = 0.0f; + + proj[8] = cam->viewOffset.x*invwx; + proj[9] = cam->viewOffset.y*invwy; + proj[12] = -proj[8]; + proj[13] = -proj[9]; + if(cam->projection == Camera::PERSPECTIVE){ + proj[10] = (cam->farPlane+cam->nearPlane)*invz; + proj[11] = 1.0f; + + proj[14] = -2.0f*cam->nearPlane*cam->farPlane*invz; + proj[15] = 0.0f; + }else{ + proj[10] = 2.0f*invz; + proj[11] = 0.0f; + + proj[14] = -(cam->farPlane+cam->nearPlane)*invz; + proj[15] = 1.0f; + } + memcpy(&cam->devProj, &proj, sizeof(RawMatrix)); + + float32 N = engine->device.zNear; + float32 F = engine->device.zFar; + // give us a small safe region for device z range + // because clipping may not be totally exact + N += (F - N)/10000.0f; + F -= (F - N)/10000.0f; + zScaleScreen = (F-N)/2.0f; + zShiftScreen = (F+N)/2.0f; + + + + fogFarPlane = cam->farPlane; +//fogFarPlane = 3.0f; +//fogFarPlane = 10.0f; + fogScale = -255.0f/(fogFarPlane - cam->fogPlane); + fogShift = -fogFarPlane*fogScale; + + // TODO: subrastering + int32 width = cam->frameBuffer->width; + int32 height = cam->frameBuffer->height; + + // in 2D we only transform cam z to fog + // and translate xy + // NB: not all of those numbers are actually used + vuConst.xyzwScale_2D.q_f[0] = 1.0f; + vuConst.xyzwScale_2D.q_f[1] = 1.0f; + vuConst.xyzwScale_2D.q_f[2] = 1.0f; + vuConst.xyzwScale_2D.q_f[3] = fogScale; + vuConst.xyzwOffset_2D.q_f[0] = 2048.0f - width/2; + vuConst.xyzwOffset_2D.q_f[1] = 2048.0f - height/2; + vuConst.xyzwOffset_2D.q_f[2] = 0.0f; + vuConst.xyzwOffset_2D.q_f[3] = fogShift; + + // in 3D we do a bit more... +#ifdef CLIP_DEBUG + vuConst.xyzwScale_3D.q_f[0] = width/4; + vuConst.xyzwScale_3D.q_f[1] = -height/4; +#else + vuConst.xyzwScale_3D.q_f[0] = width/2; + vuConst.xyzwScale_3D.q_f[1] = -height/2; +#endif +// vuConst.xyzwScale_3D.q_f[2] = zScaleScreen; + vuConst.xyzwScale_3D.q_f[2] = cam->zScale; + vuConst.xyzwScale_3D.q_f[3] = fogScale; + vuConst.xyzwOffset_3D.q_f[0] = 2048.0f; + vuConst.xyzwOffset_3D.q_f[1] = 2048.0f; +// vuConst.xyzwOffset_3D.q_f[2] = zShiftScreen; + vuConst.xyzwOffset_3D.q_f[2] = cam->zShift; + vuConst.xyzwOffset_3D.q_f[3] = fogShift; + + vuConst.clipConsts.q_f[0] = cam->fogPlane; + vuConst.clipConsts.q_f[1] = fogFarPlane; + vuConst.clipConsts.q_f[2] = cam->nearPlane; + vuConst.clipConsts.q_f[3] = cam->farPlane; +} + +void +endUpdate(Camera *cam) +{ +} + +// has to be called outside of a dma packet +void +uploadVUCode(uint32 *code) +{ + uint128 tmp; + if(code == currentVUCode) + return; + currentVUCode = code; + MAKEQ(tmp, VIFnop, VIFnop, (uint32)code, DMAcall); + vifPacket[vifPacksz++].q_u128 = tmp; +} + +// Build combined matrix from world, view and projection +void +setMatrix(RawMatrix *combined, Matrix *world) +{ + RawMatrix tmp1, tmp2; + if(world){ + convMatrix(&tmp1, world); + RawMatrix::mult(&tmp2, &tmp1, &engine->currentCamera->devView); + RawMatrix::mult(combined, &tmp2, &engine->currentCamera->devProj); + }else{ + RawMatrix::mult(combined, &engine->currentCamera->devView, &engine->currentCamera->devProj); + } +} + +static int +startPS2(void) +{ + uint128 tmp; + + colorNoScale.q_f[0] = 1.0f; + colorNoScale.q_f[1] = 1.0f; + colorNoScale.q_f[2] = 1.0f; + colorNoScale.q_f[3] = COLSCALE; + colorTexScale.q_f[0] = COLSCALE; + colorTexScale.q_f[1] = COLSCALE; + colorTexScale.q_f[2] = COLSCALE; + colorTexScale.q_f[3] = COLSCALE; + + rw::ps2::rwStateCache.addressU = rw::Texture::WRAP; + rw::ps2::rwStateCache.addressV = rw::Texture::WRAP; + rw::ps2::rwStateCache.filterMode = rw::Texture::NEAREST; + rw::ps2::rwStateCache.srcblend = rw::BLENDSRCALPHA; + rw::ps2::rwStateCache.destblend = rw::BLENDINVSRCALPHA; + rw::ps2::setAlphaBlend(rw::ps2::rwStateCache.srcblend, rw::ps2::rwStateCache.destblend); + // gouraud, no RW state for that right now + // TODO: make sure RW states and GS regs are in synch on init + rw::ps2::gsRegs.prmode |= 0x8; +// rw::ps2::gsRegs.alpha_1 = SCE_GS_SET_ALPHA(0, 1, 0, 1, 0); + rw::ps2::gsRegs.test_1 = SCE_GS_SET_TEST(0, 0, 0, 0, 0, 0, 1, 1); + + sceGsResetPath(); + sceDmaReset(1); + + // TODO: get all this stuff from videomode + gsCrtState.inter = SCE_GS_INTERLACE; + gsCrtState.mode = VIDEOMODE; + gsCrtState.ff = SCE_GS_FIELD; // SCE_GS_FRAME; + sceGsResetGraph(0, gsCrtState.inter, gsCrtState.mode, gsCrtState.ff); + + GsInitCtx(&gsCtx, SCREEN_WIDTH, SCREEN_HEIGHT, SCE_GS_PSMCT32, SCE_GS_PSMZ24); + gsStart = gsAllocPtr/4/64; + + // Enable FINISH and SIGNAL interrupts (we're not even using SIGNAL) + AddIntcHandler(INTC_GS, gsHandler, 0); + EnableIntc(INTC_GS); + *GS_CSR = GS_CSR_FINISH_M | GS_CSR_SIGNAL_M; + *GS_IMR = ~(GS_IMR_FINISHMSK_M | GS_IMR_SIGMSK_M); + + AddDmacHandler(DMAC_VIF1, dmacVif1Handler, 0); + EnableDmac(DMAC_VIF1); + + AddIntcHandler(INTC_VIF1, vif1Handler, 0); + EnableIntc(INTC_VIF1); + + dmaGif = sceDmaGetChan(SCE_DMA_GIF); + dmaGif->chcr.TTE = 0; + *GIF_MODE = 4; // IMT intermittent mode + + dmaVif = sceDmaGetChan(SCE_DMA_VIF1); + dmaVif->chcr.TTE = 1; + dmaVif->chcr.TIE = 1; + + dmaInit(); + + dmaFlip(0); + rw::ps2::InitGSregs(); + // init ROW register to write cleared ADC flag (adcHack variable) + MAKEQ(tmp, VIFstrow, VIFstmod, 0, DMAcnt + 1); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKEQ(tmp, 0, 0, 0, 0); + vifPacket[vifPacksz++].q_u128 = tmp; + dmaKick(); + sceGsSyncPath(0, 0); + + return 1; +} + +// TODO: implement the whole thing +int +deviceSystem(DeviceReq req, void *arg, int32 n) +{ + switch(req){ + case DEVICEOPEN: + // perhaps do this here? + rw::engine->filefuncs.rwfopen = ps2fopen; + rw::engine->filefuncs.rwfclose = ps2fclose; + rw::engine->filefuncs.rwfseek = ps2fseek; + rw::engine->filefuncs.rwftell = ps2ftell; + rw::engine->filefuncs.rwfread = ps2fread; + rw::engine->filefuncs.rwfwrite = ps2fwrite; + rw::engine->filefuncs.rwfeof = ps2feof; + + // before querying videomodes. probably not much to do here + break; + case DEVICECLOSE: + break; + + case DEVICEINIT: + // before plugins are constructed + return startPS2(); + case DEVICETERM: + break; + + case DEVICEFINALIZE: + // after plugins are constructed + break; + + default: + printf("system request %d not implemented\n", req); + return 0; + } + return 1; +} + +// This isn't optimal... +void +beginFrame(int frame) +{ + dmaFlip(frame&1); + GsSetDisp(&gsCtx.disp[frame&1]); + GsSetDraw(&gsCtx.draw[frame&1]); +} + +void +endFrame(float *t1, float *t2) +{ + sceGsSyncPath(0, 0); + *t1 = GetTimeF(); + // we could start uploading textures here now so they'll be ready after vsynch + + sceGsSyncV(0); + *t2 = GetTimeF(); + + dmaKick(); +} + Device renderdevice = { 16777215.0f, 0.0f, - null::beginUpdate, - null::endUpdate, - null::clearCamera, + ps2::beginUpdate, + ps2::endUpdate, + ps2::clearCamera, null::showRaster, null::rasterRenderFast, - null::setRenderState, - null::getRenderState, + ps2::setRenderState, + ps2::getRenderState, null::im2DRenderLine, null::im2DRenderTriangle, - null::im2DRenderPrimitive, - null::im2DRenderIndexedPrimitive, - null::im3DTransform, + ps2::renderPrim_VU, //im2DRenderPrimitive, + ps2::renderIndexedPrim_VU, //im2DRenderIndexedPrimitive, + ps2::vuIm3DTransform, null::im3DRenderPrimitive, - null::im3DRenderIndexedPrimitive, - null::im3DEnd, - null::deviceSystem + ps2::vuIm3DRenderIndexed, //vuIm3DRenderIndexedPrimitive, + ps2::vuIm3DEnd, + ps2::deviceSystem }; } diff --git a/src/ps2/ps2file.cpp b/src/ps2/ps2file.cpp new file mode 100644 index 0000000..3fd59a7 --- /dev/null +++ b/src/ps2/ps2file.cpp @@ -0,0 +1,124 @@ +#ifdef RW_PS2 + +#include +#include +#include +#include + +#include "../rwbase.h" + +#include + +struct FILE_PS2 +{ + int used; + int fd; + int pos; + int size; +}; +FILE_PS2 ps2files[64]; + +/* file functions */ + +void* +ps2fopen(const char *path, const char *mode) +{ + int flags = 0; + int fd; + int i; + char *r, *w, *plus; + +// printf("trying to open <%s> mode <%s>\n", path, mode); + for(i = 0; i < nelem(ps2files); i++){ + if(!ps2files[i].used) + goto found; + } + // no file pointer available + return nil; +found: + + r = strchr(mode, 'r'); + w = strchr(mode, 'w'); + plus = strchr(mode, '+'); + + if(plus) + flags = SCE_RDWR; + else if(r) + flags = SCE_RDONLY; + else if(w) + flags = SCE_WRONLY; + + if(w) + flags |= SCE_CREAT | SCE_TRUNC; + + fd = sceOpen(path, flags); + if(fd < 0) + return nil; + + ps2files[i].used = 1; + ps2files[i].fd = fd; + ps2files[i].pos = 0; + if(w){ + ps2files[i].size = 0; + }else{ + ps2files[i].size = sceLseek(fd, 0, SCE_SEEK_END); + sceLseek(fd, 0, SCE_SEEK_SET); + } + return &ps2files[i]; +} + +int +ps2fclose(void *fp) +{ + FILE_PS2 *f = (FILE_PS2*)fp; + if(!f->used) + return EOF; + sceClose(f->fd); + f->used = 0; + f->fd = -1; + return 0; +} + +int +ps2fseek(void *fp, long offset, int whence) +{ + FILE_PS2 *f = (FILE_PS2*)fp; + f->pos = sceLseek(f->fd, offset, whence); + return f->pos; +} + +long +ps2ftell(void *fp) +{ + FILE_PS2 *f = (FILE_PS2*)fp; + return f->pos; +} + +size_t +ps2fread(void *ptr, size_t size, size_t nmemb, void *fp) +{ + FILE_PS2 *f = (FILE_PS2*)fp; + int n = sceRead(f->fd, ptr, size*nmemb); + f->pos += n; + return n/size; +} + +size_t +ps2fwrite(const void *ptr, size_t size, size_t nmemb, void *fp) +{ + FILE_PS2 *f = (FILE_PS2*)fp; + int n = sceWrite(f->fd, ptr, size*nmemb); + f->pos += n; + if(f->pos > f->size) + f->size = f->pos; + return n/size; +} + +int +ps2feof(void *fp) +{ + FILE_PS2 *f = (FILE_PS2*)fp; + return f->pos >= f->size; +} + +#endif diff --git a/src/ps2/ps2file.h b/src/ps2/ps2file.h new file mode 100644 index 0000000..de53aa4 --- /dev/null +++ b/src/ps2/ps2file.h @@ -0,0 +1,7 @@ +void *ps2fopen(const char *path, const char *mode); +int ps2fclose(void *fp); +int ps2fseek(void *fp, long offset, int whence); +long ps2ftell(void *fp); +size_t ps2fread(void *ptr, size_t size, size_t nmemb, void *fp); +size_t ps2fwrite(const void *ptr, size_t size, size_t nmemb, void *fp); +int ps2feof(void *fp); diff --git a/src/ps2/ps2immed.cpp b/src/ps2/ps2immed.cpp new file mode 100644 index 0000000..64c7132 --- /dev/null +++ b/src/ps2/ps2immed.cpp @@ -0,0 +1,345 @@ +#ifdef RW_PS2 + +#include +#include +#include +#include + +#include "../rwbase.h" +#include "../rwerror.h" +#include "../rwplg.h" +#include "../rwrender.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwengine.h" +#include "../rwanim.h" +#include "../rwplugins.h" +#include "rwps2.h" +#include "rwps2plg.h" + +#include "rwps2impl.h" + +#include + +#define PLUGIN_ID 2 + +extern rw::ps2::VUdesc vu1_im3d_desc[7]; +extern rw::ps2::VUdesc vu1_im2d_desc[2]; +extern rw::uint32 vu1_im2d[]; +extern rw::uint32 vu1_im3d[]; + +namespace rw { +namespace ps2 { + +struct BatchInfo +{ + uint32 numBatches; + uint32 batchSize; + int32 repeat; +}; + +int +prologue(BatchInfo *bi, PrimitiveType type, int32 numVerts) +{ + // 2 words for GIF tags, 2 input and output buffers, 3 qw per vertex + bi->batchSize = (vuMatrix - 2)/(2*3 + 2*3); + int primsz = primSize[type]; + bi->repeat = primRepeat[type]; + int numPrims = 0; + int numPrimsBatch = 0; + switch(type){ + case PRIMTYPEPOINTLIST: + case PRIMTYPELINELIST: + case PRIMTYPETRILIST: + numPrims = numVerts/primsz; + numPrimsBatch = bi->batchSize/primsz; + numPrimsBatch &= ~3; + bi->batchSize = numPrimsBatch*primsz; + break; + case PRIMTYPEPOLYLINE: + case PRIMTYPETRISTRIP: + case PRIMTYPETRIFAN: + numPrims = numVerts - bi->repeat; + bi->batchSize &= ~3; + numPrimsBatch = bi->batchSize - bi->repeat; + break; + } + // nothing to draw + if(bi->batchSize < primSize[type]) + return 1; + + bi->numBatches = (numPrims + numPrimsBatch-1) / numPrimsBatch; + + uploadRaster(rwStateCache.raster); + setTexture(rwStateCache.raster, rwStateCache.addressU, rwStateCache.addressV, rwStateCache.filterMode); + + flushGSRegs(); + return 0; +} + +int +prologue2d(BatchInfo *bi, PrimitiveType type, int32 numVerts) +{ + uint128 tmp; + + prologue(bi, type, numVerts); + + uploadVUCode(vu1_im2d); + + // DMAcnt for everything + int dmasz = 8 // general VIF unpacks + + 3*(numVerts + (bi->numBatches-1)*bi->repeat) // vertices + + bi->numBatches*2; // batch prolog and epilog + assert(dmasz <= 0xFFFF); + MAKEQ(tmp, VIFflush, VIFflush, 0, DMAcnt + dmasz); + vifPacket[vifPacksz++].q_u128 = tmp; + + // some uploads and double buffer + uint32 offset = bi->batchSize*3; + MAKEQ(tmp, UNPACK(V4_32, 2, vuXyzwScale), STCYCL(4,4), VIFoffset + offset, VIFbase + 0); + vifPacket[vifPacksz++].q_u128 = tmp; + vifPacket[vifPacksz++] = vuConst.xyzwScale_2D; + vifPacket[vifPacksz++] = vuConst.xyzwOffset_2D; + + MAKEQ(tmp, UNPACK(V4_32, 2, vuGifTag), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, 0x412, SCE_GIF_SET_TAG(0, 1, 1,rw2gsPrim[type], SCE_GIF_PACKED, 3)); + vifPacket[vifPacksz++].q_u128 = tmp; + vifPacket[vifPacksz++] = (rwStateCache.raster == nil || doModulate2) ? colorNoScale : colorTexScale; + + MAKEQ(tmp, UNPACK(V4_32, 1, vuVuSwitch), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + VUdesc *desc = rwStateCache.fogEnable ? &vu1_im2d_desc[1] : &vu1_im2d_desc[0]; + MAKEQ(tmp, 0, 0, 0, desc->process>>3); + vifPacket[vifPacksz++].q_u128 = tmp; + + return 0; +} + +int +prologue3d(BatchInfo *bi, PrimitiveType type, int32 numVerts) +{ + uint128 tmp; + + prologue(bi, type, numVerts); + + uploadVUCode(vu1_im3d); + + // DMAcnt for everything + int dmasz = 13 // general VIF unpacks + + 3*(numVerts + (bi->numBatches-1)*bi->repeat) // vertices + + bi->numBatches*2; // batch prolog and epilog + assert(dmasz <= 0xFFFF); + MAKEQ(tmp, VIFflush, VIFflush, 0, DMAcnt + dmasz); + vifPacket[vifPacksz++].q_u128 = tmp; + + // some uploads and double buffer + uint32 offset = bi->batchSize*3; + MAKEQ(tmp, UNPACK(V4_32, 7, vuMatrix), STCYCL(4,4), VIFoffset + offset, VIFbase + 0); + vifPacket[vifPacksz++].q_u128 = tmp; + vifPacket[vifPacksz++] = vuConst.mat0; + vifPacket[vifPacksz++] = vuConst.mat1; + vifPacket[vifPacksz++] = vuConst.mat2; + vifPacket[vifPacksz++] = vuConst.mat3; + vifPacket[vifPacksz++] = vuConst.xyzwScale_3D; + vifPacket[vifPacksz++] = vuConst.xyzwOffset_3D; + vifPacket[vifPacksz++] = vuConst.clipConsts; + + MAKEQ(tmp, UNPACK(V4_32, 2, vuGifTag), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, 0x412, SCE_GIF_SET_TAG(0, 1, 1,rw2gsPrim[type], SCE_GIF_PACKED, 3)); + vifPacket[vifPacksz++].q_u128 = tmp; + vifPacket[vifPacksz++] = (rwStateCache.raster == nil || doModulate2) ? colorNoScale : colorTexScale; + + MAKEQ(tmp, UNPACK(V4_32, 1, vuVuSwitch), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + VUdesc *desc; + if(!doClipping) + desc = &vu1_im3d_desc[0]; + else if(type != PRIMTYPETRIFAN && type <= PRIMTYPEPOINTLIST) + desc = &vu1_im3d_desc[type]; + else + printf("invalid primitive type\n"); + MAKEQ(tmp, 0, desc->buf2, desc->buf1, desc->process>>3); + vifPacket[vifPacksz++].q_u128 = tmp; + + return 0; +} + +void +renderPrim_VU(PrimitiveType type, void *verts, int32 numVerts) +{ + uint128 tmp; + BatchInfo bi; + + if(prologue2d(&bi, type, numVerts)) + return; + + int i, j, vx; + Im2DVertex *v; + vx = 0; + for(i = 0; i < bi.numBatches; i++){ + int32 vertCount = numVerts; + if(vertCount > bi.batchSize) + vertCount = bi.batchSize; + + MAKEQ(tmp, UNPACK(V4_32, vertCount*3, 0x8000 + 0), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + for(j = 0; j < vertCount; j++){ + if(j == 0 && type == PRIMTYPETRIFAN) + v = &((Im2DVertex*)verts)[0]; + else + v = &((Im2DVertex*)verts)[vx]; + memcpy(&vifPacket[vifPacksz], v, 3*16); + vifPacksz += 3; + vx++; + } + uint64 call, flush; + if(i == 0) + call = UINT64(VIFmscalf + 0, VIFitop + vertCount); + else + call = UINT64(VIFmscnt, VIFitop + vertCount); + if(i == bi.numBatches-1) + flush = UINT64(VIFflush, VIFflush); + else + flush = UINT64(VIFnop, VIFnop); + MAKE128(tmp, flush, call); + vifPacket[vifPacksz++].q_u128 = tmp; + + numVerts -= vertCount; + numVerts += bi.repeat; + vx -= bi.repeat; + } +} + +void +renderIndexedPrim_VU(PrimitiveType type, void *verts, int32 numVerts, void *indices, int32 numIndices) +{ + uint128 tmp; + BatchInfo bi; + + if(prologue2d(&bi, type, numIndices)) + return; + + int i, j, ix, vx; + Im2DVertex *v; + ix = 0; + for(i = 0; i < bi.numBatches; i++){ + int32 vertCount = numIndices; + if(vertCount > bi.batchSize) + vertCount = bi.batchSize; + + MAKEQ(tmp, UNPACK(V4_32, vertCount*3, 0x8000 + 0), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + for(j = 0; j < vertCount; j++){ + if(j == 0 && type == PRIMTYPETRIFAN) + vx = ((uint16*)indices)[0]; + else + vx = ((uint16*)indices)[ix]; + v = &((Im2DVertex*)verts)[vx]; + memcpy(&vifPacket[vifPacksz], v, 3*16); + vifPacksz += 3; + ix++; + } + uint64 call, flush; + if(i == 0) + call = UINT64(VIFmscalf + 0, VIFitop + vertCount); + else + call = UINT64(VIFmscnt, VIFitop + vertCount); + if(i == bi.numBatches-1) + flush = UINT64(VIFflush, VIFflush); + else + flush = UINT64(VIFnop, VIFnop); + MAKE128(tmp, flush, call); + vifPacket[vifPacksz++].q_u128 = tmp; + + numIndices -= vertCount; + numIndices += bi.repeat; + ix -= bi.repeat; + } +} + +/********* + * VU Im3D + *********/ + +static Im3DVertex *im3dVerts; + +void +vuIm3DTransform(void *vertices, int32 numVertices, Matrix *world, uint32 flags) +{ + im3dVerts = (Im3DVertex*)vertices; + setMatrix((RawMatrix*)&vuConst.mat0, world); +} + +void +vuIm3DEnd(void) +{ +} + +void +vuIm3DRenderIndexed(PrimitiveType type, void *indices, int32 numIndices) +{ + uint128 tmp; + BatchInfo bi; + QWord q; + + if(prologue3d(&bi, type, numIndices)) + return; + + int i, j, ix, vx; + Im3DVertex *v; + ix = 0; + int first = 1; + for(i = 0; i < bi.numBatches; i++){ + int32 vertCount = numIndices; + if(vertCount > bi.batchSize) + vertCount = bi.batchSize; + + MAKEQ(tmp, UNPACK(V4_32, vertCount*3, 0x8000 + 0), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + for(j = 0; j < vertCount; j++){ + if(j == 0 && type == PRIMTYPETRIFAN) + vx = ((uint16*)indices)[0]; + else + vx = ((uint16*)indices)[ix]; + v = &im3dVerts[vx]; + q.q_f[0] = v->position.x; + q.q_f[1] = v->position.y; + q.q_f[2] = v->position.z; + q.q_f[3] = 0.0f; // ADC flag + vifPacket[vifPacksz++] = q; + q.q_f[0] = v->u; + q.q_f[1] = v->v; + q.q_f[2] = 0.0f; + q.q_f[3] = 0.0f; + vifPacket[vifPacksz++] = q; + ix++; + q.q_u32[0] = v->r; + q.q_u32[1] = v->g; + q.q_u32[2] = v->b; + q.q_u32[3] = v->a; + vifPacket[vifPacksz++] = q; + } + uint64 call, flush; + if(i == 0) + call = UINT64(VIFmscalf + 0, VIFitop + vertCount); + else + call = UINT64(VIFmscnt, VIFitop + vertCount); + if(i == bi.numBatches-1) + flush = UINT64(VIFflush, VIFflush); + else + flush = UINT64(VIFnop, VIFnop); + MAKE128(tmp, flush, call); + vifPacket[vifPacksz++].q_u128 = tmp; + + numIndices -= vertCount; + numIndices += bi.repeat; + ix -= bi.repeat; + } +} + +} +} + +#endif diff --git a/src/ps2/ps2render.cpp b/src/ps2/ps2render.cpp new file mode 100644 index 0000000..b0ba9de --- /dev/null +++ b/src/ps2/ps2render.cpp @@ -0,0 +1,248 @@ +#ifdef RW_PS2 + +#include +#include +#include +#include + +#include "../rwbase.h" +#include "../rwerror.h" +#include "../rwplg.h" +#include "../rwrender.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwengine.h" +#include "../rwanim.h" +#include "../rwplugins.h" +#include "rwps2.h" +#include "rwps2plg.h" + +#include "rwps2impl.h" + +#define PLUGIN_ID 2 + +#include + +extern rw::ps2::VUdesc vu1_default_desc[3]; +extern rw::uint32 vu1_default[]; + + + +namespace rw { +namespace ps2 { + +void +uploadLights(WorldLights *lightData, Matrix *worldMat) +{ + int i; + uint128 tmp; + QWord q; + RGBAf *col; + V3d localDir; + + int dmasz = 1; + if(lightData->numAmbients) + dmasz++; + dmasz += lightData->numDirectionals*2; + + Matrix lightmat; + if(lightData->numDirectionals || lightData->numLocals) + Matrix::invert(&lightmat, worldMat); + + assert(dmasz <= 0x3F0-0x3D0); + MAKEQ(tmp, UNPACK(V4_32, dmasz, vuLight), STCYCL(4,4), 0, DMAcnt + dmasz); + vifPacket[vifPacksz++].q_u128 = tmp; + + if(lightData->numAmbients){ + + q.q_f[0] = lightData->ambient.red*255.0f; + q.q_f[1] = lightData->ambient.green*255.0f; + q.q_f[2] = lightData->ambient.blue*255.0f; + q.q_u32[3] = 1; // ambient + vifPacket[vifPacksz++] = q; + } + for(i = 0; i < lightData->numDirectionals; i++){ + Light *l = lightData->directionals[i]; + col = &l->color; + q.q_f[0] = col->red*255.0f; + q.q_f[1] = col->green*255.0f; + q.q_f[2] = col->blue*255.0f; + q.q_u32[3] = 3; // direct + vifPacket[vifPacksz++] = q; + V3d *dir = &l->getFrame()->getLTM()->at; + V3d::transformVectors(&localDir, dir, 1, &lightmat); + q.q_f[0] = localDir.x; + q.q_f[1] = localDir.y; + q.q_f[2] = localDir.z; + q.q_f[3] = 0.0f; + vifPacket[vifPacksz++] = q; + } + + // TODO: local lights + + MAKEQ(tmp, 0, 0, 0, 0); + vifPacket[vifPacksz++].q_u128 = tmp; // end +} + +void +lightingCB(Atomic *atomic) +{ + WorldLights lightData; + Light *directionals[8]; + Light *locals[8]; + lightData.directionals = directionals; + lightData.numDirectionals = 8; + lightData.locals = locals; + lightData.numLocals = 8; + if(atomic->geometry->flags & rw::Geometry::LIGHT){ + engine->currentWorld->enumerateLights(atomic, &lightData); + if((atomic->geometry->flags & rw::Geometry::NORMALS) == 0){ + // Get rid of lights that need normals when we don't have any + lightData.numDirectionals = 0; + lightData.numLocals = 0; + } + return uploadLights(&lightData, atomic->getFrame()->getLTM()); + }else{ + memset(&lightData, 0, sizeof(lightData)); + return uploadLights(&lightData, nil); + } +} + + +int +setupAtomic(Atomic *atomic) +{ + uint128 tmp; + + setMatrix((RawMatrix*)&vuConst.mat0, atomic->getFrame()->getLTM()); + + lightingCB(atomic); + + MeshHeader *header = atomic->geometry->meshHeader; + PrimitiveType type = header->flags == rw::MeshHeader::TRISTRIP ? + rw::PRIMTYPETRISTRIP : rw::PRIMTYPETRILIST; + uploadVUCode(vu1_default); + + // DMAcnt + int dmasz = 12; // general VIF unpacks + MAKEQ(tmp, VIFflush, VIFflush, 0, DMAcnt + dmasz); + vifPacket[vifPacksz++].q_u128 = tmp; + + // some uploads + MAKEQ(tmp, UNPACK(V4_32, 7, vuMatrix), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + vifPacket[vifPacksz++] = vuConst.mat0; + vifPacket[vifPacksz++] = vuConst.mat1; + vifPacket[vifPacksz++] = vuConst.mat2; + vifPacket[vifPacksz++] = vuConst.mat3; + vifPacket[vifPacksz++] = vuConst.xyzwScale_3D; + vifPacket[vifPacksz++] = vuConst.xyzwOffset_3D; + vifPacket[vifPacksz++] = vuConst.clipConsts; + + MAKEQ(tmp, UNPACK(V4_32, 1, vuGifTag), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + MAKE128(tmp, 0x412, SCE_GIF_SET_TAG(0, 1, 1,rw2gsPrim[type], SCE_GIF_PACKED, 3)); + vifPacket[vifPacksz++].q_u128 = tmp; + + MAKEQ(tmp, UNPACK(V4_32, 1, vuVuSwitch), STCYCL(4,4), VIFnop, VIFnop); + vifPacket[vifPacksz++].q_u128 = tmp; + VUdesc *desc; + if(doClipping){ + if(type == PRIMTYPETRILIST) + desc = &vu1_default_desc[1]; + else if(type == PRIMTYPETRISTRIP) + desc = &vu1_default_desc[2]; + else + printf("invalid primitive type\n"); + }else + desc = &vu1_default_desc[0]; + MAKEQ(tmp, 0, desc->buf2, desc->buf1, desc->process>>3); + vifPacket[vifPacksz++].q_u128 = tmp; + + return 0; +} + +void +setupMaterial(Material *mat) +{ + uint128 tmp; + QWord q; + RGBAf matcol; + Texture *tex = mat->texture; + + // TODO: set texture alpha state + if(tex) + uploadRaster(tex->raster); + + // TODO: no vertex alpha, sad + rw::SetRenderState(VERTEXALPHA, mat->color.alpha != 0xFF); + + QWord scale = (tex == nil || doModulate2) ? colorNoScale : colorTexScale; + MAKEQ(tmp, UNPACK(V4_32, 2, vuColScale), STCYCL(4,4), 0, DMAcnt + 2); + vifPacket[vifPacksz++].q_u128 = tmp; + + // material color + convColor(&matcol, &mat->color); + if(tex){ + setTexture(tex->raster, tex->getAddressU(), tex->getAddressV(), tex->getFilter()); + q.q_f[0] = matcol.red*scale.q_f[0]; + q.q_f[1] = matcol.green*scale.q_f[1]; + q.q_f[2] = matcol.blue*scale.q_f[2]; + q.q_f[3] = matcol.alpha*scale.q_f[3]; + }else{ + setTexture(nil, 0, 0, 0); + q.q_f[0] = matcol.red*scale.q_f[0]; + q.q_f[1] = matcol.green*scale.q_f[1]; + q.q_f[2] = matcol.blue*scale.q_f[2]; + q.q_f[3] = matcol.alpha*scale.q_f[3]; + } + vifPacket[vifPacksz++] = q; + + // surface props + q.q_f[0] = mat->surfaceProps.ambient; + q.q_f[1] = mat->surfaceProps.specular; + q.q_f[2] = mat->surfaceProps.diffuse; + q.q_f[3] = 0.0f; + vifPacket[vifPacksz++] = q; + + flushGSRegs(); +} + +void +defaultAtomicRender(rw::ObjPipeline *pipe, Atomic *atomic) +{ + int i; + uint128 tmp; + ObjPipeline *op = (ObjPipeline*)pipe; + + Geometry *geo = atomic->geometry; + op->instance(atomic); + assert(geo->instData != nil); + assert(geo->instData->platform == PLATFORM_PS2); + + InstanceDataHeader *instData = (InstanceDataHeader*)geo->instData; + MeshHeader *header = geo->meshHeader; + + setupAtomic(atomic); + + for(i = 0; i < instData->numMeshes; i++){ + Material *mat = instData->instanceMeshes[i].material; + MatPipeline *mp = op->groupPipeline; + if(mp == nil) + mp = (MatPipeline*)mat->pipeline; + if(mp == nil) + mp = defaultMatPipe; + + // TODO: this should be a method of the pipeline + setupMaterial(mat); + + // call geometry + MAKEQ(tmp, VIFoffset+mp->vifOffset, VIFbase + 0, (uint32)instData->instanceMeshes[i].data, DMAcall); + vifPacket[vifPacksz++].q_u128 = tmp; + } +} + +} +} + +#endif diff --git a/src/ps2/ps2types.h b/src/ps2/ps2types.h new file mode 100644 index 0000000..6234fa1 --- /dev/null +++ b/src/ps2/ps2types.h @@ -0,0 +1,63 @@ +#ifdef RW_PS2 + +#include + +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef unsigned int uintptr_t; +typedef u_long128 uint128_t; + +typedef union QWord QWord; +union QWord { + u_long128 q_u128; + u_long q_u64[2]; + u_int q_u32[4]; + float q_f[4]; +}; + +#define MAKE128(RES,MSB,LSB) \ + __asm__ ( "pcpyld %0, %1, %2" : "=r" (RES) : "r" ((uint64)MSB), "r" ((uint64)LSB)) +#define UINT64(HIGH,LOW) (((uint64)(uint32)HIGH)<<32 | ((uint64)(uint32)LOW)) +#define MAKEQ(RES,W3,W2,W1,W0) MAKE128(RES,UINT64(W3,W2),UINT64(W1,W0)) + +enum { + IntFlg = 0x80000000, + + DMAcnt = 0x10000000, + DMAref = 0x30000000, + DMAcall = 0x50000000, + DMAret = 0x60000000, + DMAend = 0x70000000, + + VIFnop = 0, + VIFoffset = 0x02000000, + VIFbase = 0x03000000, + VIFitop = 0x04000000, + VIFstmod = 0x05000000, + VIFmskpath3 = 0x06008000, + VIFunmskpath3 = 0x06000000, + VIFmark = 0x07000000, + VIFflushe = 0x10000000, + VIFflush = 0x11000000, + VIFflusha = 0x13000000, + VIFmscal = 0x14000000, + VIFmscalf = 0x15000000, + VIFmscnt = 0x17000000, + VIFstmask = 0x20000000, + VIFstrow = 0x30000000, + VIFstcol = 0x31000000, + VIFdirect = 0x50000000, + + V4_32 = 0x6C +}; + +#define UNPACK(type, nq, offset) ((type)<<24 | (nq)<<16 | (offset)) +#define STCYCL(WL,CL) (0x01000000 | (WL)<<8 | (CL)) + +#endif diff --git a/src/ps2/rwgs.h b/src/ps2/rwgs.h new file mode 100644 index 0000000..80070e0 --- /dev/null +++ b/src/ps2/rwgs.h @@ -0,0 +1,53 @@ +typedef struct GsDispCtx GsDispCtx; +struct GsDispCtx +{ + // two circuits + uint64_t pmode; + uint64_t dispfb1; + uint64_t dispfb2; + uint64_t display1; + uint64_t display2; + uint64_t bgcolor; +}; + +typedef struct GsDrawCtx GsDrawCtx; +struct GsDrawCtx +{ + //two contexts + uint128_t gifTag; + uint64_t frame1; + uint64_t ad_frame1; + uint64_t frame2; + uint64_t ad_frame2; + uint64_t zbuf1; + uint64_t ad_zbuf1; + uint64_t zbuf2; + uint64_t ad_zbuf2; + uint64_t xyoffset1; + uint64_t ad_xyoffset1; + uint64_t xyoffset2; + uint64_t ad_xyoffset2; + uint64_t scissor1; + uint64_t ad_scissor1; + uint64_t scissor2; + uint64_t ad_scissor2; +}; + +typedef struct GsCtx GsCtx; +struct GsCtx +{ + // display context; two buffers + GsDispCtx disp[2]; + // draw context; two buffers + GsDrawCtx draw[2]; +}; + +typedef struct GsCrtState GsCrtState; +struct GsCrtState +{ + int16_t inter, mode, ff; +}; + +void GsSetDisp(GsDispCtx *disp); +void GsSetDraw(GsDrawCtx *draw); + diff --git a/src/ps2/rwps2.h b/src/ps2/rwps2.h index d2945e9..5d5d58c 100644 --- a/src/ps2/rwps2.h +++ b/src/ps2/rwps2.h @@ -1,3 +1,8 @@ +#ifdef RW_PS2 +#include "ps2types.h" +#include "ps2file.h" +#endif + namespace rw { #ifdef RW_PS2 @@ -277,5 +282,44 @@ Texture *readNativeTexture(Stream *stream); void writeNativeTexture(Texture *tex, Stream *stream); uint32 getSizeNativeTexture(Texture *tex); + + +#ifdef RW_PS2 +// Real hardware +// very messy atm + +void dmaFlip(int i); +void dmaKick(void); + +extern rw::uint32 gifPacksz, gifBufSize; +extern rw::uint32 vifPacksz, vifBufSize; +extern QWord *gifPacket, *vifPacket; + + +extern int path2Textures; +extern int synchTextures; +extern int gateTextures; + +extern int finishCycle; + +extern int32 doClipping; +extern int32 doModulate2; + +extern QWord colorNoScale; +extern QWord colorTexScale; + +void beginFrame(int frame); +void endFrame(float *t1, float *t2); + +void uploadRaster(Raster *raster); +void setTexture(Raster *raster, uint32 addressU, uint32 addressV, uint32 filterMode); +void flushGSRegs(void); +void uploadVUCode(uint32 *code); +void setMatrix(RawMatrix *combined, Matrix *world); + +void defaultAtomicRender(rw::ObjPipeline *pipe, Atomic *atomic); + +#endif + } } diff --git a/src/ps2/rwps2impl.h b/src/ps2/rwps2impl.h index f455bd2..6b38128 100644 --- a/src/ps2/rwps2impl.h +++ b/src/ps2/rwps2impl.h @@ -1,6 +1,104 @@ +// lower level stuff + +// this should go elsewhere +//#define PAL +#define SCREEN_WIDTH 640 +#ifdef PAL +#define SCREEN_HEIGHT 512 +#define VIDEOMODE SCE_GS_PAL +#else +#define SCREEN_HEIGHT 448 +#define VIDEOMODE SCE_GS_NTSC +#endif + + +// RW proper + namespace rw { + +#ifdef RW_PS2 +typedef uint128_t uint128; +#endif + namespace ps2 { +#ifdef RW_PS2 + +struct VUdesc +{ + uint32 process, buf1, buf2, buf3; +}; + + +extern int rw2gsPrim[]; +extern int primSize[]; +extern int primRepeat[]; + +struct RwStateCache { + Raster *raster; + uint32 addressU; + uint32 addressV; + uint32 filterMode; + + bool32 vertexAlpha; + uint32 alphaTestEnable; + uint32 alphaFunc; + bool32 textureAlpha; + bool32 blendEnable; + uint32 srcblend, destblend; + uint32 zwrite; + uint32 ztest; + uint32 cullmode; + uint32 fogEnable; + float32 fogStart; + float32 fogEnd; +}; +extern RwStateCache rwStateCache; + +enum { + vuLight = 0x3D0, + vuMatrix = 0x3F0, + vuXyzwScale = 0x3F4, + vuXyzwOffset = 0x3F5, + vuClipConsts = 0x3F6, + + vuGifTag = 0x3FA, + vuColScale = 0x3FB, + vuSurfProps = 0x3FC, + vuVuSwitch = 0x3FF +}; + +struct VuConst { + QWord mat0, mat1, mat2, mat3; + QWord xyzwScale_2D; + QWord xyzwOffset_2D; + QWord xyzwScale_3D; + QWord xyzwOffset_3D; + QWord clipConsts; + + QWord gifTag; + QWord surfProps; + QWord vuSwitch; +}; +extern VuConst vuConst; + + +// The reset should be private + +void renderPrim_VU(PrimitiveType type, void *verts, int32 numVerts); +void renderIndexedPrim_VU(PrimitiveType type, void *verts, int32 numVerts, void *indices, int32 numIndices); +void vuIm3DTransform(void *vertices, int32 numVertices, Matrix *world, uint32 flags); +void vuIm3DRenderIndexed(PrimitiveType type, void *indices, int32 numIndices); +void vuIm3DEnd(void); +void clearCamera(Camera *cam, RGBA *col, uint32 mode); +void beginUpdate(Camera *cam); +void endUpdate(Camera *cam); +void setRenderState(int32 state, void *pvalue); +void *getRenderState(int32 state); +int deviceSystem(DeviceReq req, void *arg, int32 n); + +#endif + Raster *rasterCreate(Raster *raster); uint8 *rasterLock(Raster*, int32 level, int32 lockMode); void rasterUnlock(Raster*, int32 level); diff --git a/src/ps2/vu1/LLclip.vu b/src/ps2/vu1/LLclip.vu new file mode 100644 index 0000000..ecedce6 --- /dev/null +++ b/src/ps2/vu1/LLclip.vu @@ -0,0 +1,79 @@ + nop xtop vi02 ; input pointer + nop xitop vi04 ; vertex count +LLClipLoop: + nop iaddiu vi03,vi00,0 ; clipped vertex count + nop iadd vi09,vi00,vi02 ; clipPtr, can do this in-place + nop lq vf24,clipConsts(vi00) ; [fogNear, fogFar, near, far] +LLClipPrimLoop: + nop lq vf01,0+0*numInAttribs(vi02) ; - load pos[0] + nop lq vf03,0+1*numInAttribs(vi02) ; - load pos[1] + addw.x vf02,vf00,vf00 nop ; make bary1 + addw.y vf04,vf00,vf00 move.yz vf02,vf00 ; make bary2 - make bary1 + mulax acc,vf28,vf01 move.xz vf04,vf00 ; xform pos[0] - make bary2 + madday acc,vf29,vf01 nop + maddaz acc,vf30,vf01 iaddiu vi02,vi02,2*numInAttribs ; - next input segment + maddw vf01,vf31,vf00 isubiu vi04,vi04,2 + mulax acc,vf28,vf03 nop ; xform pos[1] + madday acc,vf29,vf03 nop + maddaz acc,vf30,vf03 nop + maddw vf03,vf31,vf00 nop + nop nop + nop nop + clipw.xyz vf01,vf01 nop + clipw.xyz vf03,vf03 nop + nop nop + nop nop + nop nop + nop fcand vi01,0xFFF ; test if any vert is out of the frustum + nop ibeq vi01,vi00,LLClipAllInside ; no, all inside + + ;; Call Clipper + nop nop ; ClipLine tests clip flags in first instruction! + nop bal vi15,ClipLine ; skips return if there is a segment + nop nop + nop b LLClipNext + nop nop + +LLClipNewSeg: + ;; insert new segment here + addx.z vf01,vf00,vf00 lq vf05,1-2*numInAttribs(vi02) ; clear ADC - load st[0] + addx.z vf03,vf00,vf00 lq vf06,1-1*numInAttribs(vi02) ; clear ADC - load st[1] + nop lq vf07,2-2*numInAttribs(vi02) ; - load rgba[0] + nop lq vf08,2-1*numInAttribs(vi02) ; - load rgba[1] + mulax acc,vf05,vf02 nop ; interpolate st[0] + maddy vf09,vf06,vf02 sq vf01,0+0*numInAttribs(vi09) ; - store clip[0] + mulax acc,vf07,vf02 nop ; interpolate rgba[0] + maddy vf10,vf08,vf02 sq vf03,0+1*numInAttribs(vi09) ; - store clip[1] + mulax acc,vf05,vf04 nop ; interpolate st[1] + maddy vf11,vf06,vf04 sq vf09,1+0*numInAttribs(vi09) ; - store st[0] + mulax acc,vf07,vf04 iaddiu vi03,vi03,2 ; interpolate rgba[1] - inc nClipped + maddy vf12,vf08,vf04 sq vf10,2+0*numInAttribs(vi09) ; - store rgba[0] + nop iaddiu vi09,vi09,2*numInAttribs + nop sq vf11,1-1*numInAttribs(vi09) ; - store st[1] + nop b LLClipNext + nop sq vf12,2-1*numInAttribs(vi09) ; - store rgba[1] +LLClipAllInside: + ;; segment completely inside + addx.z vf01,vf00,vf00 lq vf05,1-2*numInAttribs(vi02) ; clear ADC - load st[0] + addx.z vf03,vf00,vf00 lq vf06,1-1*numInAttribs(vi02) ; clear ADC - load st[1] + nop lq vf07,2-2*numInAttribs(vi02) ; - load rgba[0] + nop lq vf08,2-1*numInAttribs(vi02) ; - load rgba[1] + nop sq vf05,1+0*numInAttribs(vi09) ; - store st[0] + nop sq vf06,1+1*numInAttribs(vi09) ; - store st[1] + nop sq vf07,2+0*numInAttribs(vi09) ; - store rgba[0] + nop sq vf08,2+1*numInAttribs(vi09) ; - store rgba[1] + nop sq vf01,0+0*numInAttribs(vi09) ; - store clip[0] + nop sq vf03,0+1*numInAttribs(vi09) ; - store clip[1] + nop iaddiu vi03,vi03,2 ; - inc nClipped + nop iaddiu vi09,vi09,2*numInAttribs +LLClipNext: + nop ibgtz vi04,LLClipPrimLoop ; more input + nop nop + nop ibeq vi03,vi00,End ; nothing to render + nop nop + + ;; Process Clip buffer to output buffer and render + nop bal vi15,ProcessClip + nop xtop vi09 + nop b End + nop nop diff --git a/src/ps2/vu1/LSclip.vu b/src/ps2/vu1/LSclip.vu new file mode 100644 index 0000000..e5c29d0 --- /dev/null +++ b/src/ps2/vu1/LSclip.vu @@ -0,0 +1,100 @@ + nop xtop vi02 ; input pointer + nop xitop vi04 ; vertex count + nop isubiu vi04,vi04,1 ; for linestrip +LSClipLoop: + nop iaddiu vi03,vi00,0 ; clipped vertex count + nop iaddiu vi09,vi00,clipBuf ; clipPtr + nop lq vf24,clipConsts(vi00) ; [fogNear, fogFar, near, far] + nop iaddiu vi08,vi00,1 ; restartStrip flag +LSClipPrimLoop: + nop lq vf01,0+0*numInAttribs(vi02) ; - load pos[0] + nop lq vf03,0+1*numInAttribs(vi02) ; - load pos[1] + addw.x vf02,vf00,vf00 ilw.w vi15,0+1*numInAttribs(vi02) ; make bary1 - load pos[1].w, ADC flag + addw.y vf04,vf00,vf00 isubiu vi04,vi04,1 ; make bary2 + mulax acc,vf28,vf01 nop ; xform pos[0] + madday acc,vf29,vf01 ibltz vi04,LSClipRender ; - this could only really happen the first time + maddaz acc,vf30,vf01 iaddiu vi02,vi02,numInAttribs ; - next input segment + maddw vf01,vf31,vf00 ibne vi15,vi00,LSClipSkip ; - this segment is marked, skip it + mulax acc,vf28,vf03 ior vi08,vi08,vi15 ; xform pos[1] - also set restart flag + madday acc,vf29,vf03 nop + maddaz acc,vf30,vf03 nop + maddw vf03,vf31,vf00 nop + nop nop + nop nop + clipw.xyz vf01,vf01 move.yz vf02,vf00 ; - make bary1 + clipw.xyz vf03,vf03 move.xz vf04,vf00 ; - mark bary2 + nop nop + nop nop + nop nop + nop fcand vi01,0xFFF ; test if any vert is out of the frustum + nop ibeq vi01,vi00,LSClipAllInside ; no, all inside + + ;; Call Clipper + nop nop ; ClipLine tests clip flags in first instruction! + nop bal vi15,ClipLine ; skips return if there is a segment + nop nop + nop b LSClipSkip + nop iaddiu vi08,vi00,1 ; have to restart strip + +LSClipNewSeg: + ;; insert new segment here + nop loi 2048.0 + addi.z vf01,vf00,i lq vf05,1-1*numInAttribs(vi02) ; set ADC - load st[0 + addx.z vf03,vf00,vf00 lq vf06,1-0*numInAttribs(vi02) ; clear ADC - load st[1] + nop lq vf07,2-1*numInAttribs(vi02) ; - load rgba[0] + nop lq vf08,2-0*numInAttribs(vi02) ; - load rgba[1] + mulax acc,vf05,vf02 iaddiu vi08,vi00,1 ; interpolate st[0] - have to restart strip + maddy vf09,vf06,vf02 sq vf01,0+0*numInAttribs(vi09) ; - store clip[0] + mulax acc,vf07,vf02 nop ; interpolate rgba[0] + maddy vf10,vf08,vf02 sq vf03,0+1*numInAttribs(vi09) ; - store clip[1] + mulax acc,vf05,vf04 nop ; interpolate st[1] + maddy vf11,vf06,vf04 sq vf09,1+0*numInAttribs(vi09) ; - store st[0] + mulax acc,vf07,vf04 iaddiu vi03,vi03,2 ; interpolate rgba[1] - inc nClipped + maddy vf12,vf08,vf04 sq vf10,2+0*numInAttribs(vi09) ; - store rgba[0] + nop iaddiu vi09,vi09,2*numInAttribs + nop sq vf11,1-1*numInAttribs(vi09) ; - store st[1] + nop b LSClipPrimEnd + nop sq vf12,2-1*numInAttribs(vi09) ; - store rgba[1] + +LSClipAllInside: + nop ibeq vi08,vi00,LSClipContStrip + nop loi 2048.0 + addi.z vf01,vf00,i lq vf05,1-1*numInAttribs(vi02) ; clear ADC - load st[0] + nop lq vf07,2-1*numInAttribs(vi02) ; - load rgba[0] + nop iaddiu vi03,vi03,1 ; - inc nClipped + nop iaddiu vi09,vi09,numInAttribs + nop sq vf05,1-1*numInAttribs(vi09) ; - store st[0] + nop sq vf07,2-1*numInAttribs(vi09) ; - store rgba[0] + nop sq vf01,0-1*numInAttribs(vi09) ; - store clip[0] +LSClipContStrip: + addx.z vf03,vf00,vf00 lq vf06,1-0*numInAttribs(vi02) ; clear ADC - load st[1] + nop lq vf08,2-0*numInAttribs(vi02) ; - load rgba[1] + nop iaddiu vi03,vi03,1 ; - inc nClipped + nop iaddiu vi09,vi09,numInAttribs + nop sq vf06,1-1*numInAttribs(vi09) ; - store st[1] + nop sq vf08,2-1*numInAttribs(vi09) ; - store rgba[1] + nop sq vf03,0-1*numInAttribs(vi09) ; - store clip[1] + nop iaddiu vi08,vi00,0 ; we'll be in a strip after this + +LSClipPrimEnd: + ;; TODO: don't use clipVertLimitTS + nop isubiu vi15,vi03,clipVertLimitTS ; can we overflow next time? + nop nop + nop ibgtz vi15,LSClipRender ; yes, have to render +LSClipSkip: + nop nop + nop ibgtz vi04,LSClipPrimLoop ; next segment + nop nop +LSClipRender: + nop ibeq vi03,vi00,End ; nothing to render + nop nop + + ;; Process Clip buffer to output buffer and render + nop bal vi15,ProcessClip + nop iaddiu vi09,vi00,clipBuf + + nop iblez vi04,End ; no more verts to process + nop nop + nop b LSClipLoop ; next batch + nop nop + diff --git a/src/ps2/vu1/PointCull.vu b/src/ps2/vu1/PointCull.vu new file mode 100644 index 0000000..f85408a --- /dev/null +++ b/src/ps2/vu1/PointCull.vu @@ -0,0 +1,35 @@ + nop xtop vi02 ; input pointer + nop xitop vi04 ; vertex count + nop lq vf10,0(vi02) ; load pos + nop iadd vi03,vi00,vi00 ; nClipped + nop iadd vi09,vi00,vi02 ; we're culling in-place + mulaw acc,vf31,vf00 nop +PCullLoop: + maddax acc,vf28,vf10 lq vf02,1(vi02) ; xform pos - load st + madday acc,vf29,vf10 lq vf03,2(vi02) ; - load rgba + maddz vf01,vf30,vf10 nop + nop iaddiu vi02,vi02,numInAttribs + nop isubiu vi04,vi04,1 + nop lq vf10,0(vi02) ; load next pos + clipw.xyz vf01,vf01 nop ; check if clipped + addx.z vf01,vf00,vf00 nop ; clear ADC + nop nop + mulaw acc,vf31,vf00 nop + nop fcand vi01,0x3F ; test if vert is out of the frustum + nop ibne vi01,vi00,PCullSkip ; yup, skip it + nop sq vf01,0(vi09) ; - store clip + nop sq vf02,1(vi09) ; - store st + nop sq vf03,2(vi09) ; - store rgba + nop iaddiu vi03,vi03,1 ; - inc nClipped + nop iaddiu vi09,vi09,numInAttribs +PCullSkip: + nop ibne vi04,vi00,PCullLoop ; more input + nop nop + nop ibeq vi03,vi00,End ; nothing to render + nop nop + + ;; Process Clip buffer to output buffer and render + nop bal vi15,ProcessClip + nop xtop vi09 + nop b End + nop nop diff --git a/src/ps2/vu1/TLclip.vu b/src/ps2/vu1/TLclip.vu new file mode 100644 index 0000000..bfcfe28 --- /dev/null +++ b/src/ps2/vu1/TLclip.vu @@ -0,0 +1,182 @@ +;;; Triangle List clipping +;;; Process input buffer to Clipping buffer +;;; flush Clipping buffer whenever it gets full +; vi01 +; vi02 input buffer have to save this +; vi03 nClipped +; vi04 nVerts have to save this +; vi05 polyInPtr +; vi06 polyInEnd +; vi07 polyOutPtr +; vi08 +; vi09 clipPtr +; vi10 polyBuf1 +; vi11 polyBuf2 +; vi12 +; vi15 + nop xtop vi02 ; input pointer + nop xitop vi04 ; vertex count +TLClipLoop: + nop iaddiu vi03,vi00,0 ; clipped vertex count + nop iaddiu vi09,vi00,clipBuf ; clipPtr + nop iadd vi10,vi00,vi12 ; polyBuf1 + nop iaddiu vi11,vi10,2*10 ; polyBuf2, need some space for trailing junk + nop lq vf24,clipConsts(vi00) ; [fogNear, fogFar, near, far] +TLClipPrimLoop: + ;; We have two polygon buffers (at vi10 and vi11). + ;; For every clipping plane, clip polygon in one and generate new poly in the other + nop iadd vi05,vi00,vi10 ; polyInPtr + nop iaddiu vi06,vi05,6 ; polyInEnd + nop iadd vi07,vi00,vi11 ; polyOutPtr + + ;; init polygon buffer + nop lq vf01,0+0*numInAttribs(vi02) ; - load pos[0] + nop ilw.w vi15,0+2*numInAttribs(vi02) ; - load pos[2].w, ADC flag + nop lq vf02,0+1*numInAttribs(vi02) ; - load pos[1] + nop lq vf03,0+2*numInAttribs(vi02) ; - load pos[2] + mulax acc,vf28,vf01 nop ; xform pos[0] + madday acc,vf29,vf01 nop + maddaz acc,vf30,vf01 iaddiu vi02,vi02,3*numInAttribs ; - next input triangle + maddw vf01,vf31,vf00 isubiu vi04,vi04,3 + mulax acc,vf28,vf02 nop ; xform pos[1] + madday acc,vf29,vf02 ibltz vi04,TLClipRender + maddaz acc,vf30,vf02 mr32 vf06,vf00 ; - make bary[2] + maddw vf02,vf31,vf00 sq vf01,0(vi05) ; - store pos[0] in polybuf + mulax acc,vf28,vf03 ibne vi15,vi00,TLClipSkip ; xform pos[2] - this tri is marked, skip it + madday acc,vf29,vf03 nop + maddaz acc,vf30,vf03 mr32 vf05,vf06 ; - make bary[1] + maddw vf03,vf31,vf00 sq vf02,2(vi05) ; - store pos[1] in polybuf + ; do first clipping test (note we test the first one twice) + ; note only z-test is valid at this point because w can still be negative + clipw.xyz vf01,vf01 nop + clipw.xyz vf01,vf01 nop + clipw.xyz vf02,vf02 mr32 vf04,vf05 ; - make bary[0] + clipw.xyz vf03,vf03 sq vf03,4(vi05) ; - store pos[2] in polybuf + nop sq vf06,5(vi05) ; - store bary[2] + nop sq vf05,3(vi05) ; - store bary[1] + nop sq vf04,1(vi05) ; - store bary[0] + nop fcand vi01,0xFFFFFF ; test if any vert is out of the frustum + nop ibeq vi01,vi00,TLClipAllInside ; no, all inside + + ;; Call Clipper + nop nop + nop bal vi15,ClipTriangle ; skips return if there is a poly + nop nop + nop b TLClipSkip + nop nop + +TLClipTriangulate: + ;; interpolate vertices and create new primitives from polygon buffer here + ;; this depends on the INPUTFORMAT +/* + v0 = interp(c0); + v1 = interp(c1); + clipPtr[1] = v1; + i = 2; + do { + vi = interp(ci); + i++; + clipPtr[0] = v0; + clipPtr[2] = vi; + clipPtr += 3; + if(polyPtr == polyEnd) + break; + clipPtr[1] = vi; + } +*/ + ; vf01 - clip[0] + ; vf02 - bary[0] + ; vf03 - clip[i] + ; vf04 - bary[i] + ; input verts + ; vf10 - rgba[0] + ; vf11 - rgba[1] + ; vf12 - rgba[2] + ; vf13 - st[0] + ; vf14 - st[1] + ; vf15 - st[2] + ; vf16 - clip rgba[0] + ; vf17 - clip st[0] + ; vf18 - clip rgba[n] + ; vf19 - clip st[n] + nop lq vf04,3(vi05) ; - load bary[1] + nop ibeq vi05,vi06,TLClipSkip ; - no vertices at all + addx.z vf01,vf00,vf00 lq vf10,1-3*numInAttribs(vi02) ; clear ADC - load st[0] + addx.z vf03,vf00,vf00 lq vf11,1-2*numInAttribs(vi02) ; clear ADC - load st[1] + nop lq vf12,1-1*numInAttribs(vi02) ; - load st[2] + nop lq vf13,2-3*numInAttribs(vi02) ; - load rgba[0] + mulax acc,vf10,vf04 lq vf14,2-2*numInAttribs(vi02) ; interpolate st[1] - load rgba[1] + madday acc,vf11,vf04 lq vf15,2-1*numInAttribs(vi02) ; interpolate st[1] - load rgba[2] + maddz vf18,vf12,vf04 lq vf02,1(vi05) ; interpolate st[1] - load bary[0] + mulax acc,vf13,vf04 lq.xyw vf03,2(vi05) ; interpolate rgba[1] - load clip[1] + madday acc,vf14,vf04 lq.xyw vf01,0(vi05) ; interpolate rgba[1] - load clip[0] + maddz vf19,vf15,vf04 iaddiu vi05,vi05,4 ; interpolate rgba[1] + mulax acc,vf10,vf02 nop ; interpolate st[0] + madday acc,vf11,vf02 sq vf03,0+1*numInAttribs(vi09) ; interpolate st[0] - store clip[1] + maddz vf16,vf12,vf02 sq vf18,1+1*numInAttribs(vi09) ; interpolate st[0] - store st[1] + mulax acc,vf13,vf02 sq vf19,2+1*numInAttribs(vi09) ; interpolate rgba[0] - store rgba[1] + madday acc,vf14,vf02 nop ; interpolate rgba[0] + maddz vf17,vf15,vf02 nop ; interpolate rgba[0] +TLClipTriLoop: + ;; write one triangle here + nop lq vf04,1(vi05) ; - load bary[i] + nop lq.xyw vf03,0(vi05) ; - load clip[i] + nop sq vf01,0+0*numInAttribs(vi09) ; - store clip[0] + nop sq vf16,1+0*numInAttribs(vi09) ; - store st[0] + mulax acc,vf10,vf04 sq vf17,2+0*numInAttribs(vi09) ; interpolate st[i] - store rgba[0] + madday acc,vf11,vf04 iaddiu vi05,vi05,2 ; interpolate st[i] - inc polyPtr + maddz vf18,vf12,vf04 iaddiu vi03,vi03,3 ; interpolate st[i] - inc nClipped + mulax acc,vf13,vf04 nop ; interpolate rgba[i] + madday acc,vf14,vf04 nop ; interpolate rgba[i] + maddz vf19,vf15,vf04 sq vf03,0+2*numInAttribs(vi09) ; interpolate rgba[i] - store clip[i] + nop sq vf18,1+2*numInAttribs(vi09) ; - store st[i] + nop iaddiu vi09,vi09,3*numInAttribs ; - inc clipPtr + nop ibeq vi05,vi06,TLClipPrimEnd ; - reached the end + nop sq vf19,2-1*numInAttribs(vi09) ; - store rgba[i] + nop sq vf03,0+1*numInAttribs(vi09) ; - store clip[i] + nop sq vf18,1+1*numInAttribs(vi09) ; - store st[i] + nop b TLClipTriLoop + nop sq vf19,2+1*numInAttribs(vi09) ; - store rgba[i] + +TLClipAllInside: + ;; copy full triangle + ;; this depends on the INPUTFORMAT + nop lq vf04,1-3*numInAttribs(vi02) ; - load st[0] + nop lq vf05,1-2*numInAttribs(vi02) ; - load st[1] + nop lq vf06,1-1*numInAttribs(vi02) ; - load st[2] + nop lq vf07,2-3*numInAttribs(vi02) ; - load rgba[0] + nop lq vf08,2-2*numInAttribs(vi02) ; - load rgba[1] + nop lq vf09,2-1*numInAttribs(vi02) ; - load rgba[2] + nop sq vf04,1+0*numInAttribs(vi09) ; - store st[0] + nop sq vf05,1+1*numInAttribs(vi09) ; - store st[1] + addx.z vf01,vf00,vf00 sq vf06,1+2*numInAttribs(vi09) ; clear ADC - store st[2] + addx.z vf02,vf00,vf00 sq vf07,2+0*numInAttribs(vi09) ; clear ADC - store rgba[0] + addx.z vf03,vf00,vf00 sq vf08,2+1*numInAttribs(vi09) ; clear ADC - store rgba[1] + nop sq vf09,2+2*numInAttribs(vi09) ; - store rgba[2] + nop sq vf01,0+0*numInAttribs(vi09) ; - store clip[0] + nop sq vf02,0+1*numInAttribs(vi09) ; - store clip[1] + nop sq vf03,0+2*numInAttribs(vi09) ; - store clip[2] + nop iaddiu vi03,vi03,3 ; - inc nClipped + nop iaddiu vi09,vi09,3*numInAttribs + +TLClipPrimEnd: + nop isubiu vi15,vi03,clipVertLimitTL ; can we overflow next time? + nop nop + nop ibgtz vi15,TLClipRender ; yes, have to render +TLClipSkip: + nop nop + nop ibgtz vi04,TLClipPrimLoop ; next Triangle + nop nop +TLClipRender: + nop ibeq vi03,vi00,End + nop nop + + ;; Process Clip buffer to output buffer and render + nop bal vi15,ProcessClip + nop iaddiu vi09,vi00,clipBuf + + nop iblez vi04,End ; no more verts to process + nop nop + nop b TLClipLoop ; next batch + nop nop + diff --git a/src/ps2/vu1/TSclip.vu b/src/ps2/vu1/TSclip.vu new file mode 100644 index 0000000..0573d75 --- /dev/null +++ b/src/ps2/vu1/TSclip.vu @@ -0,0 +1,187 @@ +;;; Triangle List clipping +;;; Process input buffer to Clipping buffer +;;; flush Clipping buffer whenever it gets full +; vi01 +; vi02 input buffer have to save this +; vi03 nClipped +; vi04 nVerts have to save this +; vi05 polyInPtr +; vi06 polyInEnd +; vi07 polyOutPtr +; vi08 +; vi09 clipPtr +; vi10 polyBuf1 +; vi11 polyBuf2 +; vi12 +; vi15 + nop xtop vi02 ; input pointer + nop xitop vi04 ; vertex count + nop isubiu vi04,vi04,2 ; for tristrip +TSClipLoop: + nop iaddiu vi03,vi00,0 ; clipped vertex count + nop iaddiu vi09,vi00,clipBuf ; clipPtr + nop iadd vi10,vi00,vi12 ; polyBuf1 + nop iaddiu vi11,vi10,2*10 ; polyBuf2, need some space for trailing junk + nop lq vf24,clipConsts(vi00) ; [fogNear, fogFar, near, far] + nop iaddiu vi08,vi00,1 ; restartStrip flag +TSClipPrimLoop: + ;; We have two polygon buffers (at vi10 and vi11). + ;; For every clipping plane, clip polygon in one and generate new poly in the other + nop iadd vi05,vi00,vi10 ; polyInPtr + nop iaddiu vi06,vi05,6 ; polyInEnd + nop iadd vi07,vi00,vi11 ; polyOutPtr + + ;; init polygon buffer + nop lq vf10,0+0*numInAttribs(vi02) ; - load pos[0] + nop ilw.w vi15,0+2*numInAttribs(vi02) ; - load pos[2].w, ADC flag + nop lq vf11,0+1*numInAttribs(vi02) ; - load pos[1] + nop lq vf12,0+2*numInAttribs(vi02) ; - load pos[2] + mulax acc,vf28,vf10 isubiu vi04,vi04,1 ; xform pos[0] + madday acc,vf29,vf10 iaddiu vi02,vi02,numInAttribs ; - next input triangle + maddaz acc,vf30,vf10 ibltz vi04,TSClipRender ; - this could only really happen the first time + maddw vf01,vf31,vf00 nop + mulax acc,vf28,vf11 ibne vi15,vi00,TSClipSkip ; xform pos[1] - this tri is marked, skip it + madday acc,vf29,vf11 ior vi08,vi08,vi15 ; - also set restart flag + maddaz acc,vf30,vf11 mr32 vf06,vf00 ; - make bary[2] + maddw vf02,vf31,vf00 sq vf01,0(vi05) ; - store pos[0] in polybuf + mulax acc,vf28,vf12 nop ; xform pos[2] + madday acc,vf29,vf12 nop + maddaz acc,vf30,vf12 mr32 vf05,vf06 ; - make bary[1] + maddw vf03,vf31,vf00 sq vf02,2(vi05) ; - store pos[1] in polybuf + ; do first clipping test (note we test the first one twice) + ; note only z-test is valid at this point because w can still be negative + clipw.xyz vf01,vf01 nop + clipw.xyz vf01,vf01 nop + clipw.xyz vf02,vf02 mr32 vf04,vf05 ; - make bary[0] + clipw.xyz vf03,vf03 sq vf03,4(vi05) ; - store pos[2] in polybuf + sub.xyz vf13,vf11,vf10 sq vf06,5(vi05) ; get vectors for zero-area test - store bary[2] + sub.xyz vf14,vf12,vf10 sq vf05,3(vi05) ; - store bary[1] + nop sq vf04,1(vi05) ; - store bary[0] + nop fcand vi01,0xFFFFFF ; test if any vert is out of the frustum + nop ibeq vi01,vi00,TSClipAllInside ; no, all inside + +;;; TEMP? cull degenerate tris that can become visible from clipping +.if 1 +.if 1 + opmula.xyz acc,vf13,vf14 iaddiu vi15,vi00,0xE + opmsub.xyz vf00,vf14,vf13 nop + nop nop + nop nop + nop nop + nop fmand vi01,vi15 + nop ibeq vi01,vi15,TSClipZeroArea +.else ;; less efficient unless maybe it can be inserted above somewhere + sub.xyz vf00,vf11,vf10 nop + nop nop + sub.xyz vf00,vf12,vf10 nop + nop iaddiu vi15,vi00,0xE + sub.xyz vf00,vf11,vf12 fmand vi01,vi15 + nop ibeq vi01,vi15,TSClipZeroArea + nop fmand vi01,vi15 + nop ibeq vi01,vi15,TSClipZeroArea + nop fmand vi01,vi15 + nop ibeq vi01,vi15,TSClipZeroArea +.endif +.endif + + ;; Call Clipper + nop nop + nop bal vi15,ClipTriangle ; skips return if there is a poly + nop nop + nop b TSClipSkip + nop iaddiu vi08,vi00,1 ; have to restart strip + +TSClipTriangulate: + ;; interpolate vertices and create new primitives from polygon buffer here + ;; this depends on the INPUTFORMAT + nop ibeq vi05,vi06,TSClipSkip ; - no vertices at all + nop iaddiu vi08,vi00,1 ; - have to restart strip + nop loi 2048.0 + addi.z vf01,vf00,i lq vf10,1-1*numInAttribs(vi02) ; insert first two with ADC - load st[0] + addi.z vf02,vf00,i lq vf11,1-0*numInAttribs(vi02) ; - load st[1] + nop lq vf12,1+1*numInAttribs(vi02) ; - load st[2] + nop lq vf13,2-1*numInAttribs(vi02) ; - load rgba[0] + nop lq vf14,2-0*numInAttribs(vi02) ; - load rgba[1] + nop lq vf15,2+1*numInAttribs(vi02) ; - load rgba[2] + nop lq vf03,1(vi05) ; - bary1 + nop lq vf04,-1(vi06) ; - bary2 + nop lq.xyw vf01,0(vi05) ; - clip1 + nop lq.xyw vf02,-2(vi06) ; - clip2 +TSClipTriLoop: + nop iaddiu vi08,vi00,1 ; - have to restart strip + mulax acc,vf10,vf03 iaddiu vi05,vi05,2 ; interpolate st1 + madday acc,vf11,vf03 isubiu vi07,vi06,2 + maddz vf16,vf12,vf03 iaddiu vi03,vi03,1 ; inc nClipped + mulax acc,vf13,vf03 sq vf01,0+0*numInAttribs(vi09) ; interpolate rgba1 - store clip1 + madday acc,vf14,vf03 lq.xyw vf01,0(vi05) ; - next clip1 + maddz vf17,vf15,vf03 lq vf03,1(vi05) ; - next bary1 + mulax acc,vf10,vf04 lq vf05,-3(vi06) ; interpolate st2 - next bary2 + madday acc,vf11,vf04 lq.xyw vf06,-4(vi06) + maddz vf18,vf12,vf04 sq vf16,1+0*numInAttribs(vi09) ; - store rgba1 + mulax acc,vf13,vf04 sq vf17,2+0*numInAttribs(vi09) ; interpolate rgba2 - store st1 + madday acc,vf14,vf04 ibeq vi05,vi06,TSClipPrimEnd + maddz vf19,vf15,vf04 iaddiu vi09,vi09,numInAttribs + + addx vf04,vf05,vf00 iaddiu vi03,vi03,1 ; advance bary2 + addx.xyw vf02,vf06,vf00 sq vf02,0+0*numInAttribs(vi09) ; advance clip2 - store clip2 + nop sq vf18,1+0*numInAttribs(vi09) ; - store st2 + nop sq vf19,2+0*numInAttribs(vi09) ; - store rgba2 + addx.z vf01,vf00,vf00 ibeq vi05,vi06,TSClipPrimEnd ; insert all others without ADC + addx.z vf02,vf00,vf00 iaddiu vi09,vi09,numInAttribs + nop b TSClipTriLoop + nop nop + +TSClipZeroArea: + nop b TSClipSkip + nop iaddiu vi08,vi00,1 ; - have to restart strip + nop nop ; make assembler happy + +TSClipAllInside: + ;; copy full triangle + ;; this depends on the INPUTFORMAT + nop ibeq vi08,vi00,TSClipContStrip + nop loi 2048.0 + ;; Have to restart the strip here + nop lq vf04,1-1*numInAttribs(vi02) ; - load st[0] + nop lq vf05,1-0*numInAttribs(vi02) ; - load st[1] + addi.z vf01,vf00,i lq vf07,2-1*numInAttribs(vi02) ; set ADC - load rgba[0] + addi.z vf02,vf00,i lq vf08,2-0*numInAttribs(vi02) ; set ADC - load rgba[1] + nop sq vf04,1+0*numInAttribs(vi09) ; - store st[0] + nop sq vf05,1+1*numInAttribs(vi09) ; - store st[1] + nop sq vf07,2+0*numInAttribs(vi09) ; - store rgba[0] + nop sq vf08,2+1*numInAttribs(vi09) ; - store rgba[1] + nop sq vf01,0+0*numInAttribs(vi09) ; - store clip[0] + nop sq vf02,0+1*numInAttribs(vi09) ; - store clip[1] + nop iaddiu vi03,vi03,2 ; - inc nClipped + nop iaddiu vi09,vi09,2*numInAttribs + nop iaddiu vi08,vi00,0 ; we ll be in a strip after this +TSClipContStrip: + addx.z vf03,vf00,vf00 lq vf06,1+1*numInAttribs(vi02) ; clear ADC - load st[2] + nop lq vf09,2+1*numInAttribs(vi02) ; - load rgab[2] + nop iaddiu vi03,vi03,1 ; - inc nClipped + nop iaddiu vi09,vi09,numInAttribs + nop sq vf06,1-1*numInAttribs(vi09) ; - store st[2] + nop sq vf09,2-1*numInAttribs(vi09) ; - store rgba[2] + nop sq vf03,0-1*numInAttribs(vi09) ; - store clip[2] + +TSClipPrimEnd: + nop isubiu vi15,vi03,clipVertLimitTS ; can we overflow next time? + nop nop + nop ibgtz vi15,TSClipRender ; yes, have to render +TSClipSkip: + nop nop + nop ibgtz vi04,TSClipPrimLoop ; next Triangle + nop nop +TSClipRender: + nop ibeq vi03,vi00,End ; nothing to render + nop nop + + ;; Process Clip buffer to output buffer and render + nop bal vi15,ProcessClip + nop iaddiu vi09,vi00,clipBuf + + nop iblez vi04,End ; no more verts to process + nop nop + nop b TSClipLoop ; next batch + nop nop + diff --git a/src/ps2/vu1/clipline.vu b/src/ps2/vu1/clipline.vu new file mode 100644 index 0000000..855241e --- /dev/null +++ b/src/ps2/vu1/clipline.vu @@ -0,0 +1,230 @@ +;;;;;;;;;;;; +;;;;;;; Perspective Line Segment Clipper +;;;;;;;;;;; + +;; TODO? start interpolating earlier and test the clipping flags later + +;;;; Uses the following registers +;; +;; vi01 tmp +;; vi15 tmp (return address) +;; +;; vf01 p1 pos input +;; vf02 p1 bary input +;; vf03 p2 pos input +;; vf04 p2 bary input +;; vf05 interp pos +;; vf06 interp bary +;; vf07.w d2 +;; vf08.w d1 +;; vf09.w d1-d2 +ClipLine: + +.if 1 +;;; ====== w = near plane ====== + nop fcor vi01,negZo2 ; test if both out + sub.w vf09,vf01,vf03 ibne vi01,vi00,CullLine ; d1-d2 - yes, skip this segment completely + subz.w vf07,vf01,vf24 fcand vi01,negZn2 ; d1 - test if both in + subz.w vf08,vf03,vf24 ibeq vi01,vi00,LClipNegZ_End ; d2 - yes, no need to clip against this plane + ;; So we need to interpolate + nop nop + nop div q,vf00w,vf09w + mulaw acc,vf03,vf07 nop ; interp pos (acc = p2*d1) + msubw vf05,vf01,vf08 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf07 nop ; interp bary (acc = p2*d1) + msubw vf06,vf02,vf08 nop ; interp bary (acc - p1*d2) + nop nop + nop nop + mulq vf05,vf05,q nop ; interp pos + mulq vf06,vf06,q nop ; interp bary + nop fcand vi01,negZn1 ; test p2's cliping + nop ibeq vi01,vi00,LClipNegZ_p1 ; it's in, so p1 is out + ;; p2 is out, so replace it + nop nop + clipw.xyz vf01,vf01 move vf03,vf05 + nop b LClipNegZ_Done + clipw.xyz vf05,vf05 move vf04,vf06 +LClipNegZ_p1: ;; p1 is out, so replace it + clipw.xyz vf05,vf05 move vf01,vf05 + clipw.xyz vf03,vf03 move vf02,vf06 +LClipNegZ_Done: + nop nop ; wait for clipping flags + nop nop + nop nop +LClipNegZ_End: +.endif + +.if 1 +;;; ====== w = far plane ====== + nop fcor vi01,posZo2 ; test if both out + sub.w vf09,vf03,vf01 ibne vi01,vi00,CullLine ; d1-d2 - yes, skip this segment completely + sub.w vf07,vf24,vf01 fcand vi01,posZn2 ; d1 - test if both in + sub.w vf08,vf24,vf03 ibeq vi01,vi00,LClipPosZ_End ; d2 - yes, no need to clip against this plane + ;; So we need to interpolate + nop nop + nop div q,vf00w,vf09w + mulaw acc,vf03,vf07 nop ; interp pos (acc = p2*d1) + msubw vf05,vf01,vf08 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf07 nop ; interp bary (acc = p2*d1) + msubw vf06,vf02,vf08 nop ; interp bary (acc - p1*d2) + nop nop + nop nop + mulq vf05,vf05,q nop ; interp pos + mulq vf06,vf06,q nop ; interp bary + nop fcand vi01,posZn1 ; test p2's cliping + nop ibeq vi01,vi00,LClipPosZ_p1 ; it's in, so p1 is out + ;; p2 is out, so replace it + nop nop + clipw.xyz vf01,vf01 move vf03,vf05 + nop b LClipPosZ_Done + clipw.xyz vf05,vf05 move vf04,vf06 +LClipPosZ_p1: ;; p1 is out, so replace it + clipw.xyz vf05,vf05 move vf01,vf05 + clipw.xyz vf03,vf03 move vf02,vf06 +LClipPosZ_Done: + nop nop ; wait for clipping flags + nop nop + nop nop +LClipPosZ_End: +.endif + +.if 1 +;;; ====== w = -x ====== + addax.w acc,vf01,vf01 fcor vi01,negXo2 ; test if both out + msubax.w acc,vf00,vf03 ibne vi01,vi00,CullLine ; yes, skip this segment completely + msub.w vf09,vf00,vf03 fcand vi01,negXn2 ; d1-d2 test if both in + addx.w vf07,vf01,vf01 ibeq vi01,vi00,LClipNegX_End ; d1 yes, no need to clip against this plane + ;; So we need to interpolate + addx.w vf08,vf03,vf03 nop ; d2 + nop nop + nop div q,vf00w,vf09w + mulaw acc,vf03,vf07 nop ; interp pos (acc = p2*d1) + msubw vf05,vf01,vf08 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf07 nop ; interp bary (acc = p2*d1) + msubw vf06,vf02,vf08 nop ; interp bary (acc - p1*d2) + nop nop + nop nop + mulq vf05,vf05,q nop ; interp pos + mulq vf06,vf06,q nop ; interp bary + nop fcand vi01,negXn1 ; test p2's cliping + nop ibeq vi01,vi00,LClipNegX_p1 ; it's in, so p1 is out + ;; p2 is out, so replace it + nop nop + clipw.xyz vf01,vf01 move vf03,vf05 + nop b LClipNegX_Done + clipw.xyz vf05,vf05 move vf04,vf06 +LClipNegX_p1: ;; p1 is out, so replace it + clipw.xyz vf05,vf05 move vf01,vf05 + clipw.xyz vf03,vf03 move vf02,vf06 +LClipNegX_Done: + nop nop ; wait for clipping flags + nop nop + nop nop +LClipNegX_End: +.endif + +.if 1 +;;; ====== w = x ====== + subax.w acc,vf01,vf01 fcor vi01,posXo2 ; test if both out + maddax.w acc,vf00,vf03 ibne vi01,vi00,CullLine ; yes, skip this segment completely + msub.w vf09,vf00,vf03 fcand vi01,posXn2 ; d1-d2 - test if both in + subx.w vf07,vf01,vf01 ibeq vi01,vi00,LClipPosX_End ; d1 - yes, no need to clip against this plane + ;; So we need to interpolate + subx.w vf08,vf03,vf03 nop ; d2 + nop nop + nop div q,vf00w,vf09w + mulaw acc,vf03,vf07 nop ; interp pos (acc = p2*d1) + msubw vf05,vf01,vf08 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf07 nop ; interp bary (acc = p2*d1) + msubw vf06,vf02,vf08 nop ; interp bary (acc - p1*d2) + nop nop + nop nop + mulq vf05,vf05,q nop ; interp pos + mulq vf06,vf06,q nop ; interp bary + nop fcand vi01,posXn1 ; test p2's cliping + nop ibeq vi01,vi00,LClipPosX_p1 ; it's in, so p1 is out + ;; p2 is out, so replace it + nop nop + clipw.xyz vf01,vf01 move vf03,vf05 + nop b LClipPosX_Done + clipw.xyz vf05,vf05 move vf04,vf06 +LClipPosX_p1: ;; p1 is out, so replace it + clipw.xyz vf05,vf05 move vf01,vf05 + clipw.xyz vf03,vf03 move vf02,vf06 +LClipPosX_Done: + nop nop ; wait for clipping flags + nop nop + nop nop +LClipPosX_End: +.endif + +.if 1 +;;; ====== w = -y ====== + adday.w acc,vf01,vf01 fcor vi01,negYo2 ; test if both out + msubay.w acc,vf00,vf03 ibne vi01,vi00,CullLine ; yes, skip this segment completely + msub.w vf09,vf00,vf03 fcand vi01,negYn2 ; d1-d2 - test if both in + addy.w vf07,vf01,vf01 ibeq vi01,vi00,LClipNegY_End ; d1 - yes, no need to clip against this plane + ;; So we need to interpolate + addy.w vf08,vf03,vf03 nop ; d2 + nop nop + nop div q,vf00w,vf09w + mulaw acc,vf03,vf07 nop ; interp pos (acc = p2*d1) + msubw vf05,vf01,vf08 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf07 nop ; interp bary (acc = p2*d1) + msubw vf06,vf02,vf08 nop ; interp bary (acc - p1*d2) + nop nop + nop nop + mulq vf05,vf05,q nop ; interp pos + mulq vf06,vf06,q nop ; interp bary + nop fcand vi01,negYn1 ; test p2's cliping + nop ibeq vi01,vi00,LClipNegY_p1 ; it's in, so p1 is out + ;; p2 is out, so replace it + nop nop + clipw.xyz vf01,vf01 move vf03,vf05 + nop b LClipNegY_Done + clipw.xyz vf05,vf05 move vf04,vf06 +LClipNegY_p1: ;; p1 is out, so replace it + clipw.xyz vf05,vf05 move vf01,vf05 + clipw.xyz vf03,vf03 move vf02,vf06 +LClipNegY_Done: + nop nop ; wait for clipping flags + nop nop + nop nop +LClipNegY_End: +.endif + +.if 1 +;;; ====== w = y ====== + subay.w acc,vf01,vf01 fcor vi01,posYo2 ; test if both out + madday.w acc,vf00,vf03 ibne vi01,vi00,CullLine ; yes, skip this segment completely + msub.w vf09,vf00,vf03 fcand vi01,posYn2 ; d1-d2 - test if both in + suby.w vf07,vf01,vf01 ibeq vi01,vi00,LClipPosY_End ; d2 - yes, no need to clip against this plane + ;; So we need to interpolate + suby.w vf08,vf03,vf03 nop ; d2 + nop nop + nop div q,vf00w,vf09w + mulaw acc,vf03,vf07 nop ; interp pos (acc = p2*d1) + msubw vf05,vf01,vf08 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf07 nop ; interp bary (acc = p2*d1) + msubw vf06,vf02,vf08 nop ; interp bary (acc - p1*d2) + nop nop + nop nop + mulq vf05,vf05,q nop ; interp pos + mulq vf06,vf06,q nop ; interp bary + nop fcand vi01,posYn1 ; test p2's cliping + nop ibeq vi01,vi00,LClipPosY_p1 ; it's in, so p1 is out + ;; p2 is out, so replace it + nop nop + clipw.xyz vf01,vf01 move vf03,vf05 + nop b LClipPosY_End + clipw.xyz vf05,vf05 move vf04,vf06 +LClipPosY_p1: ;; p1 is out, so replace it + clipw.xyz vf05,vf05 move vf01,vf05 + clipw.xyz vf03,vf03 move vf02,vf06 +LClipPosY_End: +.endif + + nop iaddiu vi15,vi15,2 +CullLine: + nop jr vi15 + nop nop diff --git a/src/ps2/vu1/cliptri.vu b/src/ps2/vu1/cliptri.vu new file mode 100644 index 0000000..9a0f00d --- /dev/null +++ b/src/ps2/vu1/cliptri.vu @@ -0,0 +1,272 @@ + +;;;;;;;;;;;; +;;;;;;; Perspective Triangle Clipper +;;;;;;;;;;; + +;;;; Uses the following registers +;; +;; vi01 tmp +;; vi05 polyInPtr input +;; vi06 polyInEnd input +;; vi07 polyOutPtr input +;; vi10 polyBuf1 input +;; vi11 polyBuf2 input +;; vi15 tmp (return address) +;; +;; vf01 p2 pos input +;; vf02 interp pos +;; vf03 p1 pos input +;; vf04 p2 bary +;; vf05 interp bary +;; vf06 p1 bary input +;; vf07.w d2 +;; vf08.w d1 +;; vf09.w d1-d2 +;; vf22 tmp +;; vf23 tmp + +ClipTriangle: + nop isw.w vi08,codeSwitch(vi00) ; save return +nop nop ;; TODO: assembler complains about hazard here. why? + nop iadd vi08,vi00,vi15 ; +.if 1 +;;; ====== w = near plane ====== + nop fcor vi01,negZo ; test if all out + nop ibne vi01,vi00,CullTri ; yes, skip this triangle completely + nop fcand vi01,negZn ; test if all in + nop ibeq vi01,vi00,ClipNegZ_Skip ; yes, no need to clip against this plane +ClipNegZ_Loop: + sub.w vf09,vf03,vf01 lq vf04,1(vi05) ; d1-d2 - load bary2 + subz.w vf08,vf03,vf24 move vf22,vf03 ; d1 - save pos1 + subz.w vf07,vf01,vf24 move vf23,vf06 ; d2 - save pos2 + addx vf03,vf01,vf00 iaddiu vi05,vi05,2 ; advance pos1 + nop div q,vf00w,vf09w ; - 1/(d1-d2) + mulaw acc,vf01,vf08 fsand vi01,2 ; interp pos (acc = p2*d1) get d1 sign + mul.w vf00,vf07,vf08 lq vf01,0(vi05) ; d1*d2 + msubw vf02,vf22,vf07 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf08 nop ; interp bary (acc = p2*d1) + msubw vf05,vf06,vf07 ibne vi01,vi00,ClipNegZ_Clipped ; interp bary (acc - p1*d2) + addx vf06,vf04,vf00 fsand vi15,2 ; advance bary1 - sign of d1*d2 + clipw.xyz vf22,vf22 sqi vf22,(vi07++) ; store p1 + nop sqi vf23,(vi07++) +ClipNegZ_Clipped: ; p1 is clipped + mulq vf02,vf02,q ibeq vi15,vi00,ClipNegZ_Next ; interp pos + nop iadd vi01,vi00,vi07 ; always store interp bary here + mulq vf05,vf05,q iaddiu vi07,vi07,2 ; interp bary - advance out ptr + nop nop + clipw.xyz vf02,vf02 sq vf02,-2(vi07) ; - store interp pos +ClipNegZ_Next: + nop ibne vi05,vi06,ClipNegZ_Loop + nop sq vf05,1(vi01) ; - store interp bary (or junk if no interpolation) + nop bal vi15,SwapClipBuffers + nop nop +ClipNegZ_Skip: +.endif + +.if 1 +;; Early out if all verts outside of any one plane + nop fcor vi01,posZo + nop ibne vi01,vi00,CullTri + nop fcor vi01,negXo + nop ibne vi01,vi00,CullTri + nop fcor vi01,posXo + nop ibne vi01,vi00,CullTri + nop fcor vi01,negYo + nop ibne vi01,vi00,CullTri + nop fcor vi01,posYo + nop ibne vi01,vi00,CullTri +.endif + +.if 1 +;;; ====== w = far plane ====== + nop lq vf01,0(vi05) ; load p2 pos + nop ibeq vi05,vi06,CullTri + nop fcand vi01,posZn ; test if all in + nop ibeq vi01,vi00,ClipPosZ_Skip ; yes, no need to clip against this plane + nop nop +ClipPosZ_Loop: + sub.w vf09,vf01,vf03 lq vf04,1(vi05) ; d1-d2 - load bary2 + sub.w vf08,vf24,vf03 move vf22,vf03 ; d1 - save pos1 + sub.w vf07,vf24,vf01 move vf23,vf06 ; d2 - save pos2 + addx vf03,vf01,vf00 iaddiu vi05,vi05,2 ; advance pos1 + nop div q,vf00w,vf09w ; - 1/(d1-d2) + mulaw acc,vf01,vf08 fsand vi01,2 ; interp pos (acc = p2*d1) get d1 sign + mul.w vf00,vf07,vf08 lq vf01,0(vi05) ; d1*d2 + msubw vf02,vf22,vf07 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf08 nop ; interp bary (acc = p2*d1) + msubw vf05,vf06,vf07 ibne vi01,vi00,ClipPosZ_Clipped ; interp bary (acc - p1*d2) + addx vf06,vf04,vf00 fsand vi15,2 ; sign of d1*d2 + nop sqi vf22,(vi07++) ; store p1 + nop sqi vf23,(vi07++) +ClipPosZ_Clipped: ; p1 is clipped + mulq vf02,vf02,q ibeq vi15,vi00,ClipPosZ_Next ; interp pos + nop iadd vi01,vi00,vi07 ; always store interp bary here + mulq vf05,vf05,q iaddiu vi07,vi07,2 ; interp bary - advance out ptr + nop nop + nop sq vf02,-2(vi07) ; - store interp pos +ClipPosZ_Next: + nop ibne vi05,vi06,ClipPosZ_Loop + nop sq vf05,1(vi01) ; - store interp bary (or junk if no interpolation) + nop bal vi15,SwapClipBuffers + nop nop +ClipPosZ_Skip: +.endif + +.if 1 +;;; ====== w = -x plane ====== + nop lq vf01,0(vi05) ; load p2 pos + nop ibeq vi05,vi06,CullTri + nop fcand vi01,negXn ; test if all in + addax.w acc,vf03,vf03 ibeq vi01,vi00,ClipNegX_Skip ; yes, no need to clip against this plane + msubax.w acc,vf00,vf01 nop +ClipNegX_Loop: + msub.w vf09,vf00,vf01 lq vf04,1(vi05) ; d1-d2 - load bary2 + addx.w vf08,vf03,vf03 move vf22,vf03 ; d1 - save pos1 + addx.w vf07,vf01,vf01 move vf23,vf06 ; d2 - save pos2 + addx vf03,vf01,vf00 iaddiu vi05,vi05,2 ; advance pos1 + nop div q,vf00w,vf09w ; - 1/(d1-d2) + mulaw acc,vf01,vf08 fsand vi01,2 ; interp pos (acc = p2*d1) get d1 sign + mul.w vf00,vf07,vf08 lq vf01,0(vi05) ; d1*d2 + msubw vf02,vf22,vf07 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf08 nop ; interp bary (acc = p2*d1) + msubw vf05,vf06,vf07 ibne vi01,vi00,ClipNegX_Clipped ; interp bary (acc - p1*d2) + addx vf06,vf04,vf00 fsand vi15,2 ; sign of d1*d2 + nop sqi vf22,(vi07++) ; store p1 + nop sqi vf23,(vi07++) +ClipNegX_Clipped: ; p1 is clipped + mulq vf02,vf02,q ibeq vi15,vi00,ClipNegX_Next ; interp pos + nop iadd vi01,vi00,vi07 ; always store interp bary here + mulq vf05,vf05,q iaddiu vi07,vi07,2 ; interp bary - advance out ptr + nop nop + nop sq vf02,-2(vi07) ; - store interp pos +ClipNegX_Next: + addax.w acc,vf03,vf03 ibne vi05,vi06,ClipNegX_Loop + msubax.w acc,vf00,vf01 sq vf05,1(vi01) ; - store interp bary (or junk if no interpolation) + nop bal vi15,SwapClipBuffers + nop nop +ClipNegX_Skip: +.endif + +.if 1 +;;; ====== w = +x plane ====== + nop lq vf01,0(vi05) ; load p2 pos + nop ibeq vi05,vi06,CullTri + nop fcand vi01,posXn ; test if all in + subax.w acc,vf03,vf03 ibeq vi01,vi00,ClipPosX_Skip ; yes, no need to clip against this plane + maddax.w acc,vf00,vf01 nop +ClipPosX_Loop: + msub.w vf09,vf00,vf01 lq vf04,1(vi05) ; d1-d2 - load bary2 + subx.w vf08,vf03,vf03 move vf22,vf03 ; d1 - save pos1 + subx.w vf07,vf01,vf01 move vf23,vf06 ; d2 - save pos2 + addx vf03,vf01,vf00 iaddiu vi05,vi05,2 ; advance pos1 + nop div q,vf00w,vf09w ; - 1/(d1-d2) + mulaw acc,vf01,vf08 fsand vi01,2 ; interp pos (acc = p2*d1) get d1 sign + mul.w vf00,vf07,vf08 lq vf01,0(vi05) ; d1*d2 + msubw vf02,vf22,vf07 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf08 nop ; interp bary (acc = p2*d1) + msubw vf05,vf06,vf07 ibne vi01,vi00,ClipPosX_Clipped ; interp bary (acc - p1*d2) + addx vf06,vf04,vf00 fsand vi15,2 ; sign of d1*d2 + nop sqi vf22,(vi07++) ; store p1 + nop sqi vf23,(vi07++) +ClipPosX_Clipped: ; p1 is clipped + mulq vf02,vf02,q ibeq vi15,vi00,ClipPosX_Next ; interp pos + nop iadd vi01,vi00,vi07 ; always store interp bary here + mulq vf05,vf05,q iaddiu vi07,vi07,2 ; interp bary - advance out ptr + nop nop + nop sq vf02,-2(vi07) ; - store interp pos +ClipPosX_Next: + subax.w acc,vf03,vf03 ibne vi05,vi06,ClipPosX_Loop + maddax.w acc,vf00,vf01 sq vf05,1(vi01) ; - store interp bary (or junk if no interpolation) + nop bal vi15,SwapClipBuffers + nop nop +ClipPosX_Skip: +.endif + +.if 1 +;;; ====== w = -y plane ====== + nop lq vf01,0(vi05) ; load p2 pos + nop ibeq vi05,vi06,CullTri + nop fcand vi01,negYn ; test if all in + adday.w acc,vf03,vf03 ibeq vi01,vi00,ClipNegY_Skip ; yes, no need to clip against this plane + msubay.w acc,vf00,vf01 nop +ClipNegY_Loop: + msub.w vf09,vf00,vf01 lq vf04,1(vi05) ; d1-d2 - load bary2 + addy.w vf08,vf03,vf03 move vf22,vf03 ; d1 - save pos1 + addy.w vf07,vf01,vf01 move vf23,vf06 ; d2 - save pos2 + addx vf03,vf01,vf00 iaddiu vi05,vi05,2 ; advance pos1 + nop div q,vf00w,vf09w ; - 1/(d1-d2) + mulaw acc,vf01,vf08 fsand vi01,2 ; interp pos (acc = p2*d1) get d1 sign + mul.w vf00,vf07,vf08 lq vf01,0(vi05) ; d1*d2 + msubw vf02,vf22,vf07 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf08 nop ; interp bary (acc = p2*d1) + msubw vf05,vf06,vf07 ibne vi01,vi00,ClipNegY_Clipped ; interp bary (acc - p1*d2) + addx vf06,vf04,vf00 fsand vi15,2 ; sign of d1*d2 + nop sqi vf22,(vi07++) ; store p1 + nop sqi vf23,(vi07++) +ClipNegY_Clipped: ; p1 is clipped + mulq vf02,vf02,q ibeq vi15,vi00,ClipNegY_Next ; interp pos + nop iadd vi01,vi00,vi07 ; always store interp bary here + mulq vf05,vf05,q iaddiu vi07,vi07,2 ; interp bary - advance out ptr + nop nop + nop sq vf02,-2(vi07) ; - store interp pos +ClipNegY_Next: + adday.w acc,vf03,vf03 ibne vi05,vi06,ClipNegY_Loop + msubay.w acc,vf00,vf01 sq vf05,1(vi01) ; - store interp bary (or junk if no interpolation) + nop bal vi15,SwapClipBuffers + nop nop +ClipNegY_Skip: +.endif + +.if 1 +;;; ====== w = +y plane ====== + nop lq vf01,0(vi05) ; load p2 pos + nop ibeq vi05,vi06,CullTri + nop fcand vi01,posYn ; test if all in + subay.w acc,vf03,vf03 ibeq vi01,vi00,ClipPosY_Skip ; yes, no need to clip against this plane + madday.w acc,vf00,vf01 nop +ClipPosY_Loop: + msub.w vf09,vf00,vf01 lq vf04,1(vi05) ; d1-d2 - load bary2 + suby.w vf08,vf03,vf03 move vf22,vf03 ; d1 - save pos1 + suby.w vf07,vf01,vf01 move vf23,vf06 ; d2 - save pos2 + addx vf03,vf01,vf00 iaddiu vi05,vi05,2 ; advance pos1 + nop div q,vf00w,vf09w ; - 1/(d1-d2) + mulaw acc,vf01,vf08 fsand vi01,2 ; interp pos (acc = p2*d1) get d1 sign + mul.w vf00,vf07,vf08 lq vf01,0(vi05) ; d1*d2 + msubw vf02,vf22,vf07 nop ; interp pos (acc - p1*d2) + mulaw acc,vf04,vf08 nop ; interp bary (acc = p2*d1) + msubw vf05,vf06,vf07 ibne vi01,vi00,ClipPosY_Clipped ; interp bary (acc - p1*d2) + addx vf06,vf04,vf00 fsand vi15,2 ; sign of d1*d2 + nop sqi vf22,(vi07++) ; store p1 + nop sqi vf23,(vi07++) +ClipPosY_Clipped: ; p1 is clipped + mulq vf02,vf02,q ibeq vi15,vi00,ClipPosY_Next ; interp pos + nop iadd vi01,vi00,vi07 ; always store interp bary here + mulq vf05,vf05,q iaddiu vi07,vi07,2 ; interp bary - advance out ptr + nop nop + nop sq vf02,-2(vi07) ; - store interp pos +ClipPosY_Next: + subay.w acc,vf03,vf03 ibne vi05,vi06,ClipPosY_Loop + madday.w acc,vf00,vf01 sq vf05,1(vi01) ; - store interp bary (or junk if no interpolation) + nop bal vi15,SwapClipBuffers + nop nop +ClipPosY_Skip: +.endif + nop iaddiu vi08,vi08,2 +CullTri: + nop jr vi08 + nop ilw.w vi08,codeSwitch(vi00) + +;;;;;;;;;;;; +;;;;;;; End of Perspective Triangle Clipper +;;;;;;;;;;; + +SwapClipBuffers: + nop iadd vi05,vi00,vi11 ; polyInPtr + nop iadd vi06,vi00,vi07 ; polyInEnd + nop iadd vi07,vi00,vi10 ; polyOutPtr + nop iadd vi11,vi00,vi10 + nop iadd vi10,vi00,vi05 + nop lq vf03,-2(vi06) ; load last vertex as p1 + nop jr vi15 + nop lq vf06,-1(vi06) + diff --git a/src/ps2/vu1/defaultPipe.dsm b/src/ps2/vu1/defaultPipe.dsm new file mode 100644 index 0000000..80bbcd1 --- /dev/null +++ b/src/ps2/vu1/defaultPipe.dsm @@ -0,0 +1,131 @@ +.equ vertexTop, 0x3d0 +.equ numInAttribs, 4 +.equ numOutAttribs, 3 +.equ numOutBuf, 2 +.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf)) +.equ offset, (vertCount*numInAttribs) +.equ outBuf1, (2*offset) +;.equ outSize, ((vertexTop-outBuf1-numOutBuf)/numOutBuf) +.equ outSize, (1 + vertCount*numOutAttribs) +.equ outBuf2, (outBuf1+outSize) + +.equ clipVertCount, ((vertexTop-outBuf1-numOutBuf)/(numInAttribs+numOutAttribs*numOutBuf)) +.equ clipOutSize, (1 + clipVertCount*numOutAttribs) +.equ clipOutBuf2, (outBuf1+clipOutSize) +.equ clipBuf, (clipOutBuf2+clipOutSize) + +; up to 9 verts => 7 tris per poly in worst case, a lot for lists unfortunately +.equ clipVertLimitTL, (clipVertCount-21) +.equ clipVertLimitTS, (clipVertCount-15) ;;; TODO: this crashes when i set it to -9 as it should be + +.include "defines.inc" + +#define IN_VERTEX(n,r) 0 + (n)*numInAttribs(r) +#define IN_UV(n,r) 1 + (n)*numInAttribs(r) +#define IN_RGBA(n,r) 2 + (n)*numInAttribs(r) +#define IN_NORMAL(n,r) 3 + (n)*numInAttribs(r) + +#define OUT_STQ(n,r) 0 + (n)*numOutAttribs(r) +#define OUT_RGBA(n,r) 1 + (n)*numOutAttribs(r) +#define OUT_XYZ(n,r) 2 + (n)*numOutAttribs(r) + +.balign 16,0 + +.global vu1_default +vu1_default: + +DMAret * +MPG 0, * +.vu +start: + nop ilw.y vi12,codeSwitch(vi00) + nop ilw.z vi13,codeSwitch(vi00) + nop lq vf28,matrix0(vi00) + nop lq vf29,matrix1(vi00) + nop lq vf30,matrix2(vi00) + nop lq vf31,matrix3(vi00) + nop lq vf27,xyzwScale(vi00) + nop lq vf26,xyzwOffset(vi00) + nop lq vf25,colorScale(vi00) + nop lq vf24,clipConsts(vi00) +restart: + nop ilw.x vi09,codeSwitch(vi00) ; process switch + + ;; Calculate end of input buffer with vertex count rounded up to multiple of 4 + ;; Note that the maximum vertex count is always a multiple of 4 so this is always legal + nop xtop vi02 ; input pointer + nop xitop vi01 ; vertex count + nop iaddiu vi03,vi01,3 + nop iaddiu vi04,vi00,~3 + nop iand vi04,vi03,vi04 ; round up vertex count + nop iadd vi03,vi02,vi04 +.rept numInAttribs-1 + nop iadd vi03,vi03,vi04 +.endr + + ;; Convert normals and colors to float. this is also where we d do skinning probably + ;; TODO: could simplify this if we have no lighting + nop iaddiu vi02,vi02,4*numInAttribs + nop loi 0.007874015748031496 ; normal scale + nop lq vf01,IN_RGBA(0-4,vi02) + sub vf09,vf00,vf00 lq vf02,IN_RGBA(1-4,vi02) + nop lq vf03,IN_RGBA(2-4,vi02) + nop lq vf04,IN_RGBA(3-4,vi02) +PreprocLoop: + itof0 vf01,vf01 lq vf05,IN_NORMAL(0-4,vi02) + itof0 vf02,vf02 lq vf06,IN_NORMAL(1-4,vi02) + itof0 vf03,vf03 lq vf07,IN_NORMAL(2-4,vi02) + itof0 vf04,vf04 lq vf08,IN_NORMAL(3-4,vi02) + itof0.xyz vf05,vf05 sq vf01,IN_RGBA(0-4,vi02) + itof0.xyz vf06,vf06 sq vf02,IN_RGBA(1-4,vi02) + itof0.xyz vf07,vf07 sq vf03,IN_RGBA(2-4,vi02) + itof0.xyz vf08,vf08 sq vf04,IN_RGBA(3-4,vi02) + muli.xyz vf05,vf05,i lq vf01,IN_RGBA(0,vi02) + muli.xyz vf06,vf06,i lq vf02,IN_RGBA(1,vi02) + muli.xyz vf07,vf07,i lq vf03,IN_RGBA(2,vi02) + muli.xyz vf08,vf08,i lq vf04,IN_RGBA(3,vi02) + nop sq vf05,IN_NORMAL(0-4,vi02) + nop sq vf06,IN_NORMAL(1-4,vi02) + nop sq vf07,IN_NORMAL(2-4,vi02) + nop sq vf08,IN_NORMAL(3-4,vi02) +.if 0 + ;; clear ADC flag here if geometry doesn t write it + nop sq.w vf09,IN_VERTEX(0-4,vi02) + nop sq.w vf09,IN_VERTEX(1-4,vi02) + nop sq.w vf09,IN_VERTEX(2-4,vi02) + nop sq.w vf09,IN_VERTEX(3-4,vi02) +.endif + nop ibne vi02,vi03,PreprocLoop + nop iaddiu vi02,vi02,4*numInAttribs + + +#include "lighting.vu" + + nop jr vi09 + nop nop + +Process: +#include "default_proc.vu" +TLClip: +#include "TLclip.vu" +TSClip: +#include "TSclip.vu" + +End: + nop[e] nop + nop nop + nop b restart + nop nop + +#include "cliptri.vu" +#include "default_clipproc.vu" + +.EndMPG +.EndDmaData + + +.global vu1_default_desc +vu1_default_desc: + .word Process, outBuf1, outBuf2, 0 + .word TLClip, outBuf1, clipOutBuf2, 0 + .word TSClip, outBuf1, clipOutBuf2, 0 diff --git a/src/ps2/vu1/default_clipproc.vu b/src/ps2/vu1/default_clipproc.vu new file mode 100644 index 0000000..a73a41b --- /dev/null +++ b/src/ps2/vu1/default_clipproc.vu @@ -0,0 +1,46 @@ + +;; Process clipping buffer to output +;; vertices are already in clip space +;; vi09: input buffer +;; vi03: vertex Count +;; CANNOT use: vi02, vi04 (clipping), vi15 (return) +;; TMP: vi06 +ProcessClip: + nop lq vf01,gifTag(vi00) ; GIF tag + nop iaddiu vi06,vi00,0x4000 + nop iadd vi06,vi06,vi06 ; EOP bit + nop ior vi06,vi06,vi03 ; enter vertex count + nop sq vf01,0(vi12) ; store GIF tag + nop isw.x vi06,0(vi12) + addw.z vf12,vf00,vf00 lq.xyw vf10,0(vi09) ; xyw + addw.z vf10,vf00,vf00 lq vf11,2(vi09) ; rgba + nop lq.xy vf12,1(vi09) ; st + nop iaddiu vi05,vi12,1 ; output pointer +ProcessClipLoop: + miniy.w vf01,vf10,vf24 div q,vf00w,vf10w ; clamp to fog far - start perspective division + nop nop + mul.xyz vf22,vf10,vf27 lq.z vf13,0(vi09) ; pos.xyz*scale.xyz - load ADC flag + addax acc,vf26,vf00 nop ; init acc + maxx.w vf01,vf01,vf24 nop ; clamp to fog near + ftoi0 vf02,vf11 isubiu vi03,vi03,1 ; convert rgba + maddaz.w acc,vf00,vf13 iaddiu vi09,vi09,numInAttribs ; add ADC flag + maddq.xyz vf01,vf22,q nop ; calc pos (can use q now) + madd.w vf01,vf01,vf27 nop ; calc fog + mulq.xyz vf03,vf12,q lq.xyw vf10,0(vi09) ; scale stq - next xyw + addw.z vf12,vf00,vf00 lq vf11,2(vi09) ; - next rgba + addw.z vf10,vf00,vf00 lq.xy vf12,1(vi09) ; - next st + ftoi4 vf01,vf01 iaddiu vi05,vi05,numOutAttribs ; convert xyzf + nop sq vf02,1-numOutAttribs(vi05) ; rgba + nop sq vf03,0-numOutAttribs(vi05) ; stq + nop ibne vi03,vi00,ProcessClipLoop + nop sq vf01,2-numOutAttribs(vi05) ; xyzf + + ;; Render it + nop xgkick vi12 + nop iadd vi05,vi00,vi12 + nop iadd vi12,vi00,vi13 + nop iadd vi13,vi00,vi05 + + nop jr vi15 + nop nop + diff --git a/src/ps2/vu1/default_proc.vu b/src/ps2/vu1/default_proc.vu new file mode 100644 index 0000000..eb83a74 --- /dev/null +++ b/src/ps2/vu1/default_proc.vu @@ -0,0 +1,38 @@ + mul.xyw vf23,vf31,vf27 xtop vi02 ; scale matrix - input pointer + mul.xyw vf20,vf28,vf27 lq vf10,IN_VERTEX(0,vi02) ; scale matrix - load vert-1 + mul.xyw vf21,vf29,vf27 lq vf01,gifTag(vi00) ; scale matrix + mul.xyw vf22,vf30,vf27 xitop vi01 ; scale matrix - vertex count + mulaw acc,vf23,vf00 iaddiu vi05,vi00,0x4000 ; xform vert-1 + maddax acc,vf20,vf10 iadd vi05,vi05,vi05 ; xform vert-1 - EOP bit + madday acc,vf21,vf10 ior vi05,vi05,vi01 ; xform vert-1 - enter vertex count + maddz.xyw vf01,vf22,vf10 sq vf01,0(vi12) ; xform vert-1 - store GIF tag + mulw.xy vf06,vf24,vf27 move.z vf01,vf27 ; scale fog clamp - init z-1 + add.w vf05,vf26,vf10 isw.x vi05,0(vi12) ; add adc-1 to w-offset - store vertex count + nop lq vf10,IN_VERTEX(1,vi02) ; - load vert-2 + nop div q,vf27w,vf01w ; - divide vert-1 + miniy.w vf01,vf01,vf06 nop ; clamp fog-1 + nop lq.xy vf12,IN_UV(0,vi02) ; - load uv-1 + mulaw acc,vf23,vf00 lq vf11,IN_RGBA(0,vi02) ; xform vert-2 - load rgba-1 + maddax acc,vf20,vf10 mr32.z vf12,vf00 ; xform vert-2 + maxx.w vf04,vf01,vf06 move.xyz vf05,vf26 ; clamp fog-1 + madday acc,vf21,vf10 iaddiu vi04,vi12,1 ; xform vert-2 - output pointer +ProcessLoop: + mulq.xyz vf04,vf01,q move.z vf01,vf27 + maddz.xyw vf01,vf22,vf10 nop + ftoi0 vf02,vf11 lq vf11,IN_RGBA(1,vi02) + mulq.xyz vf03,vf12,q lq.xy vf12,IN_UV(1,vi02) + add vf04,vf04,vf05 iaddiu vi02,vi02,numInAttribs + add.w vf05,vf26,vf10 div q,vf27w,vf01w + miniy.w vf01,vf01,vf06 lq vf10,IN_VERTEX(1,vi02) + mulaw acc,vf23,vf00 sqi vf03,(vi04++) + ftoi4 vf07,vf04 sqi vf02,(vi04++) + nop nop + maxx.w vf04,vf01,vf06 mr32.z vf12,vf00 + maddax acc,vf20,vf10 ibne vi02,vi03,ProcessLoop + madday acc,vf21,vf10 sqi vf07,(vi04++) + + nop xgkick vi12 ; draw kick + nop iadd vi15,vi00,vi12 ; swap output buffers + nop iadd vi12,vi00,vi13 + nop b End + nop iadd vi13,vi00,vi15 diff --git a/src/ps2/vu1/defines.inc b/src/ps2/vu1/defines.inc new file mode 100644 index 0000000..ab389b6 --- /dev/null +++ b/src/ps2/vu1/defines.inc @@ -0,0 +1,65 @@ +.equ light, 0x3d0 +.equ matrix0, 0x3f0 +.equ matrix1, 0x3f1 +.equ matrix2, 0x3f2 +.equ matrix3, 0x3f3 +.equ xyzwScale, 0x3f4 +.equ xyzwOffset, 0x3f5 +.equ clipConsts, 0x3f6 +.equ gifTag, 0x3fa +.equ colorScale, 0x3fb +.equ surfaceProps, 0x3fc +.equ codeSwitch, 0x3ff + +;; FCAND masks -- if register is 0, the whole poly is out +.equ posXn, (0x041041) +.equ negXn, (0x082082) +.equ posYn, (0x104104) +.equ negYn, (0x208208) +.equ posZn, (0x410410) +.equ negZn, (0x820820) +.equ posXn3, (posXn&0x3FFFF) +.equ negXn3, (negXn&0x3FFFF) +.equ posYn3, (posYn&0x3FFFF) +.equ negYn3, (negYn&0x3FFFF) +.equ posZn3, (posZn&0x3FFFF) +.equ negZn3, (negZn&0x3FFFF) +.equ posXn2, (posXn&0xFFF) +.equ negXn2, (negXn&0xFFF) +.equ posYn2, (posYn&0xFFF) +.equ negYn2, (negYn&0xFFF) +.equ posZn2, (posZn&0xFFF) +.equ negZn2, (negZn&0xFFF) +.equ posXn1, (posXn&0x3F) +.equ negXn1, (negXn&0x3F) +.equ posYn1, (posYn&0x3F) +.equ negYn1, (negYn&0x3F) +.equ posZn1, (posZn&0x3F) +.equ negZn1, (negZn&0x3F) + + +;; FCOR masks -- if register is 1, the whole poly is in +.equ posXo, (0xFBEFBE) +.equ negXo, (0xF7DF7D) +.equ posYo, (0xEFBEFB) +.equ negYo, (0xDF7DF7) +.equ posZo, (0xBEFBEF) +.equ negZo, (0x7DF7DF) +.equ posXo3, (posXo|0xFC0000) +.equ negXo3, (negXo|0xFC0000) +.equ posYo3, (posYo|0xFC0000) +.equ negYo3, (negYo|0xFC0000) +.equ posZo3, (posZo|0xFC0000) +.equ negZo3, (negZo|0xFC0000) +.equ posXo2, (posXo|0xFFF000) +.equ negXo2, (negXo|0xFFF000) +.equ posYo2, (posYo|0xFFF000) +.equ negYo2, (negYo|0xFFF000) +.equ posZo2, (posZo|0xFFF000) +.equ negZo2, (negZo|0xFFF000) +.equ posXo1, (posXo|0xFFFFC0) +.equ negXo1, (negXo|0xFFFFC0) +.equ posYo1, (posYo|0xFFFFC0) +.equ negYo1, (negYo|0xFFFFC0) +.equ posZo1, (posZo|0xFFFFC0) +.equ negZo1, (negZo|0xFFFFC0) diff --git a/src/ps2/vu1/im2d.dsm b/src/ps2/vu1/im2d.dsm new file mode 100644 index 0000000..72b16d2 --- /dev/null +++ b/src/ps2/vu1/im2d.dsm @@ -0,0 +1,123 @@ +.equ vertexTop, 0x3f0 +.equ numInAttribs, 3 +.equ numOutAttribs, 3 +.equ numOutBuf, 2 +.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf)) +.equ offset, (vertCount*numInAttribs) +.equ outBuf1, (2*offset) +;.equ outSize, ((vertexTop-outBuf1-numOutBuf)/numOutBuf) +.equ outSize, (1 + vertCount*numOutAttribs) +.equ outBuf2, (outBuf1+outSize) + +.include "defines.inc" + +#define IN_VERTEX(n,r) 0 + (n)*numInAttribs(r) +#define IN_UV(n,r) 1 + (n)*numInAttribs(r) +#define IN_RGBA(n,r) 2 + (n)*numInAttribs(r) + +#define OUT_STQ(n,r) 0 + (n)*numOutAttribs(r) +#define OUT_RGBA(n,r) 1 + (n)*numOutAttribs(r) +#define OUT_XYZ(n,r) 2 + (n)*numOutAttribs(r) + +.balign 16,0 + +.global vu1_im2d +vu1_im2d: + +DMAret * +MPG 0, * +.vu +start: + nop iaddiu vi12,vi00,outBuf1 + nop iaddiu vi13,vi00,outBuf2 + nop lq vf04,xyzwOffset(vi00) + nop lq vf05,colorScale(vi00) + nop lq vf06,colorScale(vi00) +restart: + nop ilw.x vi09,codeSwitch(vi00) ; process switch + nop xtop vi02 ; input pointer + nop jr vi09 + nop xtop vi01 ; vertex count + + +NoFog: + nop xtop vi02 ; input pointer + mulz.w vf01,vf00,vf00 lq vf13,IN_RGBA(0,vi02) ; clear ADC flag - load rgba + nop lq.xyz vf11,IN_VERTEX(0,vi02) ; - load xyz + nop lq.xyz vf02,IN_UV(0,vi02) ; - load uvq + nop lq vf03,gifTag(vi00) ; - GIF tag + itof0 vf13,vf13 xitop vi01 ; rgba to float - vertex count + add.xy vf11,vf11,vf04 iaddiu vi05,vi00,0x4000 ; add xy offset + mulz.xy vf02,vf02,vf02 iadd vi05,vi05,vi05 ; - EOP bit + nop ior vi05,vi05,vi01 ; - enter vertex count + nop sq vf03,0(vi12) ; - store GIF tag + nop isw.x vi05,0(vi12) + nop iaddiu vi03,vi12,1 ; - output pointer + nop iadd vi05,vi03,vi01 +.rept numOutAttribs-1 + nop iadd vi05,vi05,vi01 +.endr +NoFogLoop: + mul vf03,vf13,vf05 lq.xyz vf12,IN_UV(1,vi02) + nop lq vf13,IN_RGBA(1,vi02) + ftoi4.xyz vf01,vf11 lq.xyz vf11,IN_VERTEX(1,vi02) + nop iaddiu vi02,vi02,numInAttribs + ftoi0 vf03,vf03 iaddiu vi03,vi03,numOutAttribs + itof0 vf13,vf13 sq vf02,OUT_STQ(-1,vi03) + add.xy vf11,vf11,vf04 sq vf01,OUT_XYZ(-1,vi03) + mulz.xy vf02,vf12,vf12 ibne vi03,vi05,NoFogLoop + addx.z vf02,vf12,vf00 sq vf03,OUT_RGBA(-1,vi03) + nop b End + nop nop + + +Fog: + nop loi 255.0 + nop xtop vi02 ; input pointer + nop lq vf21,IN_VERTEX(0,vi02) ; - load xyzw + nop lq vf13,IN_RGBA(0,vi02) ; - load rgba + nop lq.xyz vf02,IN_UV(0,vi02) ; - load uvq + addax acc,vf04,vf00 lq vf03,gifTag(vi00) ; - GIF tag + madd vf21,vf05,vf21 xitop vi01 ; - vertex count + itof0 vf13,vf13 iaddiu vi05,vi00,0x4000 ; + nop iadd vi05,vi05,vi05 ; - EOP bit + nop ior vi05,vi05,vi01 ; - enter vertex count + minii.w vf11,vf21,i sq vf03,0(vi12) ; - store GIF tag + addx.xyz vf01,vf21,vf00 isw.x vi05,0(vi12) + nop iaddiu vi03,vi12,1 ; - output pointer + nop iadd vi05,vi03,vi01 +.rept numInAttribs-1 + nop iadd vi05,vi05,vi01 +.endr +FogLoop: + mul vf03,vf13,vf06 nop + addax acc,vf04,vf00 lq vf21,IN_VERTEX(1,vi02) + maxw.w vf01,vf11,vf00 nop + mulz.xy vf02,vf02,vf02 lq vf13,IN_RGBA(1,vi02) + ftoi0 vf03,vf03 lq.xyz vf12,IN_UV(1,vi02) + madd vf21,vf05,vf21 iaddiu vi02,vi02,numInAttribs + ftoi4 vf01,vf01 iaddiu vi03,vi03,numOutAttribs + itof0 vf13,vf13 sq vf02,OUT_STQ(-1,vi03) + addx vf02,vf12,vf00 sq vf03,OUT_RGBA(-1,vi03) + minii.w vf11,vf21,i ibne vi03,vi05,FogLoop + addx.xyz vf01,vf21,vf00 sq vf01,OUT_XYZ(-1,vi03) + nop b End + nop nop + + +End: + nop xgkick vi12 + nop iadd vi15,vi00,vi12 + nop[e] iadd vi12,vi00,vi13 + nop iadd vi13,vi00,vi15 + nop b restart + nop nop + +.EndMPG +.EndDmaData + + +.global vu1_im2d_desc +vu1_im2d_desc: + .word NoFog, 0, 0, 0 + .word Fog, 0, 0, 0 diff --git a/src/ps2/vu1/im3d.dsm b/src/ps2/vu1/im3d.dsm new file mode 100644 index 0000000..d3a967d --- /dev/null +++ b/src/ps2/vu1/im3d.dsm @@ -0,0 +1,125 @@ +.equ vertexTop, 0x3f0 +.equ numInAttribs, 3 +.equ numOutAttribs, 3 +.equ numOutBuf, 2 +.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf)) +.equ offset, (vertCount*numInAttribs) +.equ outBuf1, (2*offset) +;.equ outSize, ((vertexTop-outBuf1-numOutBuf)/numOutBuf) +.equ outSize, (1 + vertCount*numOutAttribs) +.equ outBuf2, (outBuf1+outSize) + +.equ clipVertCount, ((vertexTop-outBuf1-numOutBuf)/(numInAttribs+numOutAttribs*numOutBuf)) +.equ clipOutSize, (1 + clipVertCount*numOutAttribs) +.equ clipOutBuf2, (outBuf1+clipOutSize) +.equ clipBuf, (clipOutBuf2+clipOutSize) + +; up to 9 verts => 7 tris per poly in worst case +.equ clipVertLimitTL, (clipVertCount-21) +.equ clipVertLimitTS, (clipVertCount-15) ;;; TODO: this crashes when i set it to -9 as it should be + +.include "defines.inc" + +#define IN_VERTEX(n,r) 0 + (n)*numInAttribs(r) +#define IN_UV(n,r) 1 + (n)*numInAttribs(r) +#define IN_RGBA(n,r) 2 + (n)*numInAttribs(r) + +#define OUT_STQ(n,r) 0 + (n)*numOutAttribs(r) +#define OUT_RGBA(n,r) 1 + (n)*numOutAttribs(r) +#define OUT_XYZ(n,r) 2 + (n)*numOutAttribs(r) + +.balign 16,0 + +.global vu1_im3d +vu1_im3d: + +DMAret * +MPG 0, * +.vu +start: + nop ilw.y vi12,codeSwitch(vi00) + nop ilw.z vi13,codeSwitch(vi00) + nop lq vf28,matrix0(vi00) + nop lq vf29,matrix1(vi00) + nop lq vf30,matrix2(vi00) + nop lq vf31,matrix3(vi00) + nop lq vf27,xyzwScale(vi00) + nop lq vf26,xyzwOffset(vi00) + nop lq vf25,colorScale(vi00) + nop lq vf24,clipConsts(vi00) +restart: + nop ilw.x vi09,codeSwitch(vi00) ; process switch + + ;; Calculate end of input buffer with vertex count rounded up to multiple of 4 + ;; Note that the maximum vertex count is always a multiple of 4 so this is always legal + nop xtop vi02 ; input pointer + nop xitop vi01 ; vertex count + nop iaddiu vi03,vi01,3 + nop iaddiu vi04,vi00,~3 + nop iand vi04,vi03,vi04 ; round up vertex count + nop iadd vi03,vi02,vi04 +.rept numInAttribs-1 + nop iadd vi03,vi03,vi04 +.endr + + ;; Convert colors to float + nop iaddiu vi02,vi02,4*numInAttribs + nop lq vf01,IN_RGBA(0-4,vi02) + nop lq vf02,IN_RGBA(1-4,vi02) + nop lq vf03,IN_RGBA(2-4,vi02) + nop lq vf04,IN_RGBA(3-4,vi02) + itof0 vf01,vf01 nop + itof0 vf02,vf02 nop + itof0 vf03,vf03 nop + itof0 vf04,vf04 nop +PreprocLoop: + mul vf05,vf01,vf25 lq vf01,IN_RGBA(0,vi02) + mul vf06,vf02,vf25 lq vf02,IN_RGBA(1,vi02) + mul vf07,vf03,vf25 lq vf03,IN_RGBA(2,vi02) + mul vf08,vf04,vf25 lq vf04,IN_RGBA(3,vi02) + itof0 vf01,vf01 sq vf05,IN_RGBA(0-4,vi02) + itof0 vf02,vf02 sq vf06,IN_RGBA(1-4,vi02) + itof0 vf03,vf03 sq vf07,IN_RGBA(2-4,vi02) + itof0 vf04,vf04 sq vf08,IN_RGBA(3-4,vi02) + nop ibne vi02,vi03,PreprocLoop + nop iaddiu vi02,vi02,4*numInAttribs + + nop jr vi09 + nop nop + +Process: +#include "default_proc.vu" +TLClip: +.include "TLclip.vu" +TSClip: +.include "TSclip.vu" +LLClip: +.include "LLclip.vu" +LSClip: +.include "LSclip.vu" +PointCull: +.include "PointCull.vu" + +End: + nop[e] nop + nop nop + nop b restart + nop nop + +.include "cliptri.vu" +.include "clipline.vu" +#include "default_clipproc.vu" + +.EndMPG +.EndDmaData + +;; indexed by PrimitiveType +.global vu1_im3d_desc +vu1_im3d_desc: + .word Process, outBuf1, outBuf2, 0 ; PRIMTYPENONE + .word LLClip, outBuf1, outBuf2, 0 ; PRIMTYPELINELIST + .word LSClip, outBuf1, clipOutBuf2, 0 ; PRIMTYPEPOLYLINE + .word TLClip, outBuf1, clipOutBuf2, 0 ; PRIMTYPETRILIST + .word TSClip, outBuf1, clipOutBuf2, 0 ; PRIMTYPETRISTRIP + .word 0, 0, 0, 0 ; PRIMTYPETRIFAN TODO + .word PointCull, outBuf1, outBuf2, 0 ; PRIMTYPEPOINTLIST diff --git a/src/ps2/vu1/lighting.vu b/src/ps2/vu1/lighting.vu new file mode 100644 index 0000000..12401de --- /dev/null +++ b/src/ps2/vu1/lighting.vu @@ -0,0 +1,106 @@ +;;; Register usage: +;; vf20 light color +;; vf21 light direction +;; vf23 surfaceProps + +Lighting: + nop iaddiu vi08,vi00,light + nop lq vf23,surfaceProps(vi00) +LightLoop: + nop ilw.w vi15,0(vi08) ; load light type + nop lqi.xyz vf20,(vi08++) ; light color + nop ibeq vi15,vi00,PostLighting + nop xtop vi02 ; input pointer + nop iaddiu vi15,vi15,LightSwitch + nop jr vi15 +LightSwitch: + ;; Light type dispatch table + nop nop + nop b AmbientLight + nop nop + nop b DirectLight + nop lqi.xyz vf21,(vi08++) ; light direction + +;; Apply Ambient light +AmbientLight: + mulx.xyz vf20,vf20,vf23 iaddiu vi02,vi02,4*numInAttribs + nop lq vf01,IN_RGBA(0-4,vi02) + nop lq vf02,IN_RGBA(1-4,vi02) + nop lq vf03,IN_RGBA(2-4,vi02) + nop lq vf04,IN_RGBA(3-4,vi02) +AmbientLoop: + add vf05,vf01,vf20 lq vf01,IN_RGBA(0,vi02) + add vf06,vf02,vf20 lq vf02,IN_RGBA(1,vi02) + add vf07,vf03,vf20 lq vf03,IN_RGBA(2,vi02) + add vf08,vf04,vf20 lq vf04,IN_RGBA(3,vi02) + nop sq vf05,IN_RGBA(0-4,vi02) + nop sq vf06,IN_RGBA(1-4,vi02) + nop sq vf07,IN_RGBA(2-4,vi02) + nop sq vf08,IN_RGBA(3-4,vi02) + nop ibne vi02,vi03,AmbientLoop + nop iaddiu vi02,vi02,4*numInAttribs + nop b LightLoop + nop nop + +;; Apply Directional light +DirectLight: + sub.xyz vf21,vf00,vf21 lq vf01,IN_NORMAL(0,vi02) ; flip light directio + mulz.xyz vf20,vf20,vf23 lq vf02,IN_NORMAL(1,vi02) ; multiply color by surfProps + nop lq vf03,IN_NORMAL(2,vi02) + nop lq vf04,IN_NORMAL(3,vi02) + mul.xyz vf01,vf01,vf21 nop + mul.xyz vf02,vf02,vf21 nop + mul.xyz vf03,vf03,vf21 nop + mul.xyz vf04,vf04,vf21 nop + addy.x vf11,vf01,vf01 nop + addx.y vf11,vf02,vf02 nop + addx.z vf11,vf03,vf03 nop + addy.z vf04,vf04,vf04 mr32 vf09,vf04 +DirectLoop: + addz.x vf10,vf11,vf01 lq vf01,IN_NORMAL(0+4,vi02) + addz.y vf10,vf11,vf02 lq vf02,IN_NORMAL(1+4,vi02) + addy.z vf10,vf11,vf03 lq vf03,IN_NORMAL(2+4,vi02) + addz.w vf10,vf09,vf04 lq vf04,IN_NORMAL(3+4,vi02) + mul.xyz vf01,vf01,vf21 lq vf05,IN_RGBA(0,vi02) + mul.xyz vf02,vf02,vf21 lq vf06,IN_RGBA(1,vi02) + mul.xyz vf03,vf03,vf21 lq vf07,IN_RGBA(2,vi02) + maxx vf10,vf10,vf00 lq vf08,IN_RGBA(3,vi02) + mul.xyz vf04,vf04,vf21 nop + addy.x vf11,vf01,vf01 nop + addax acc,vf05,vf00 nop + maddx.xyz vf05,vf20,vf10 nop + addax acc,vf06,vf00 mr32 vf09,vf04 + maddy.xyz vf06,vf20,vf10 nop + addax acc,vf07,vf00 iaddiu vi02,vi02,4*numInAttribs + maddz.xyz vf07,vf20,vf10 sq vf05,IN_RGBA(0-4,vi02) + addax acc,vf08,vf00 nop + maddw.xyz vf08,vf20,vf10 sq vf06,IN_RGBA(1-4,vi02) + addx.y vf11,vf02,vf02 nop + addx.z vf11,vf03,vf03 sq vf07,IN_RGBA(2-4,vi02) + addy.z vf04,vf04,vf04 ibne vi02,vi03,DirectLoop + nop sq vf08,IN_RGBA(3-4,vi02) + nop b LightLoop + nop nop + +;;; Clamp lighting and multiply by material color +PostLighting: + nop loi 255.0 + nop lq vf01,IN_RGBA(0,vi02) + nop lq vf02,IN_RGBA(1,vi02) + nop lq vf03,IN_RGBA(2,vi02) + nop lq vf04,IN_RGBA(3,vi02) + minii vf05,vf01,i iaddiu vi02,vi02,4*numInAttribs + minii vf06,vf02,i nop + minii vf07,vf03,i nop + minii vf08,vf04,i nop +PostLightLoop: + mul vf05,vf05,vf25 lq vf01,IN_RGBA(0,vi02) + mul vf06,vf06,vf25 lq vf02,IN_RGBA(1,vi02) + mul vf07,vf07,vf25 lq vf03,IN_RGBA(2,vi02) + mul vf08,vf08,vf25 lq vf04,IN_RGBA(3,vi02) + minii vf05,vf01,i sq vf05,IN_RGBA(0-4,vi02) + minii vf06,vf02,i sq vf06,IN_RGBA(1-4,vi02) + minii vf07,vf03,i sq vf07,IN_RGBA(2-4,vi02) + minii vf08,vf04,i sq vf08,IN_RGBA(3-4,vi02) + nop ibne vi02,vi03,PostLightLoop + nop iaddiu vi02,vi02,4*numInAttribs