struct rxNodePS2AllPvtData { RwChar data1[16]; // TODO: figure this out RxPipelineNodePS2AllObjectSetupCallBack setupCB; RxPipelineNodePS2AllObjectFinalizeCallBack finalizeCB; RxPipeline *groupPipe; RwInt32 lightBufferOffset; RwInt32 lightBufferSize; RwUInt32 *dmaPacket; RwChar dmabuf[48]; }; #define ROUND(ptr,bnd) \ ((void*)(((RwUInt32)(ptr) + ((bnd)-1)) & ~((bnd)-1))) RwBool PS2AllNodeInstance(RxPS2AllPipeData *p2apd) { int i; int batchSize, batchesPerTag, numBatches; struct rxNodePS2AllMatPvtData *matPvtData; rwPS2AllResEntryHeader *p2rh; RwUInt32 numVerts; RwResEntry *rsnt; RwUInt32 resEntrySize; void *clusterData[CL_MAXCL+FMADD]; rwPS2AllFieldRec fieldRec[CL_MAXCL+FMADD]; void *data; int dataoffset; RwBool res; rwPS2AllClusterQuickInfo *clqi; matPvtData = p2apd->matPvtData; p2rh = RWPS2ALLRESENTRYHEADERFROMRESENTRY(*(p2apd->cacheEntryRef)); /* Check for full (re)instance */ if(p2apd->meshInstance & (rxINSTANCECONGRUENTINSTANCE | rxINSTANCEFULLINSTANCE)){ p2apd->meshInstance |= rxINSTANCEALL; RPMESHPS2ALLCALCNUMVERTS(p2apd, &numVerts); resEntrySize = DMADataSizeRecalc(p2apd, numVerts, fieldRec, &batchSize, &batchesPerTag, &numBatches); rsnt = *p2apd->cacheEntryRef; if(rsnt){ rsnt->ownerRef = NULL; *p2apd->cacheEntryRef = NULL; } *p2apd->cacheEntryRef = matPvtData->resEntryAllocCB(p2apd, p2apd->cacheEntryRef, resEntrySize, reDestroyCallBack); if(*p2apd->cacheEntryRef == NULL) return FALSE; p2rh = RWPS2ALLRESENTRYHEADERFROMRESENTRY(*(p2apd->cacheEntryRef)); p2rh->refCnt = 0; p2rh->clrcnt = 0; p2rh->objIdentifier = p2apd->objIdentifier; p2apd->meshIdentifier = RPMESHPS2ALLMAKEMESHID(p2apd->meshHeader); p2rh->meshIdentifier = p2apd->meshIdentifier; p2rh->numVerts = numVerts; for(i = 0; i < p2apd->fastMorphing+CL_MAXCL; i++) p2rh->fieldRec[i] = fieldRec[i]; p2rh->batchSize = batchSize; p2rh->numBatches = numBatches; p2rh->batchesPerTag = batchesPerTag; p2rh->morphNum = 1; p2rh->morphStart = 0; p2rh->morphFinish = 0; data = ROUND(p2rh+1, 0x40); if(matPvtData->totallyOpaque) data = ROUND(data, 0x80); p2rh->data = data; /* Set up data pointers for stripe data. */ clqi = p2rh->clquickinfo; for(i = 0; i < p2apd->fastMorphing+CL_MAXCL; i++){ if((matPvtData->clinfo[i].attrib & CL_ATTRIB_REQUIRED) && !(matPvtData->clinfo[i].attrib & CL_ATTRIB_OPAQUE)){ if(p2apd->fastMorphing) dataoffset = p2rh->fieldRec[i].morphDataoffset; else dataoffset = p2rh->fieldRec[i].dataoffset; clqi->data = p2rh->data + dataoffset; clqi->stride = matPvtData->clinfo[i].stride*4; clqi++; } } DMADataFillTags(p2apd); } if(i = 0; i < matPvtData->numStripes; i++) clusterData[i] = p2rh->clquickinfo[i].data; res = matPvtData->instanceCB(p2apd, clusterData, matPvtData->numStripes); rsnt = *p2apd->cacheEntryRef; SyncDCache(p2rh->data, (char*)rsnt + rsnt->size + 0xdb); return res; } RwBool PS2AllNodeBody(RxPipelineNode *self, const RxPipelineNodeParam *params) { RxPS2AllPipeData pipeData; rxNodePS2AllPvtData *pvtData; RwMatrix transform, *transformp; RwUInt32 *tmp; RxPipeline *defPipe; RpMeshHeader *header; RpMesh *mesh; RpMaterial *mat; RxPipeline *matpipe; RwResEntry *res; RwInt32 i; pvtData = (rxNodePS2AllPvtData*)self->privateData; _rwSkyLightFillPos = (RwReal*)(_rwSkyLightBuffer + 1); _rwSkyLightQWordsWritten = 0; pipeData.primType = 0xFF; pipeData.transType = 0; pipeData.matModulate = 0; pipeData.sourceObject = RxPipelineNodeParamGetData(params); pipeData.numMorphTargets = 1; pipeData.objPvtData = pvtData; pipeData.matPvtData = NULL; pipeData.objInstance = rxINSTANCEDONTINSTANCE; pipeData.objIdentifier = 0; pipeData.spExtra = 0.0f; pipeData.fastMorphing = 0; pipeData.meshHeader = NULL; pipeData.meshCache = NULL; transformp = &transform; defPipe = GETDEFAULTPIPE(); // TODO if(!pvtData->setupCB(&pipeData, &transformp)) return TRUE; if(pipeData.numMorphTargets >= 2) pipeData.fastMorphing = 2; // setup lighting if(_rwSkyLightQWordsWritten == 0){ // clear light data (leave matrix) _rwSkyLightQWordsWritten = 2; _rwSkyLightFillPos = (RwReal*)pvtData->dmaPacket; }else if(_rwSkyLightQWordsWritten == -1){ // let everything persist - no uploads into light block _rwSkyLightQWordsWritten = 0; }else{ if(_rwSkyLightQWordsWritten == -5){ // let lights persist but update inverse matrix _rwSkyLightQWordsWritten = 4; }else{ // copy end-of-list memcpy(_rwSkyLightFillPos, pvtData->dmaPacket+4, 16); _rwSkyLightQWordsWritten = 1; } // fill in unpack vifcode tmp = (RwUInt32*)_rwSkyLightBuffer; tmp[0] = 0; tmp[1] = 0; tmp[2] = 0x01000404; // STCYCL tmp[3] = 0x6C000000 | pvtData->lightBufferOffset | (_rwSkyLightQWordsWritten<<16); _rwSkyLightQWordsWritten++; _rwSkyLightFillPos = (RwReal*)_rwSkyLightBuffer; } openVU1SetupPktNew(transformp, _rwSkyLightFillPos, _rwSkyLightQWordsWritten); header = pipeData->meshHeader; mesh = (RpMesh*)((RwChar*)(header+1) + header->firstMeshOffset); for(i = 0; i < header->numMeshes; i++){ mat = mesh->material; if(pvtData->groupPipe) matpipe = pvtData->groupPipe; else matpipe = material->pipeline ? material->pipeline : defPipe; if(matpipe) pipeData->matPvtData = (rxNodePS2AllMatPvtData*)matpipe->nodes->privateData; pipeData->mesh = mesh; pipeData->meshInstance = pipeData->objInstance; pipeData->vu1CodeIndex = pipeData->objInstance & 0x1F; pipeData->texture = mat->texture; pipeData->surfProps = &mat->surfaceProps; pipeData->cacheEntryRef = &pipeData->meshCache->meshes[i]; pipeData->matCol = { 0xFF, 0xFF, 0xFF, 0xFF }; if(pipeData->matModulate) pipeData->matCol = material->color; if(pipeData->objInstance != rxINSTANCEDONTINSTANCE){ pipeData->meshInstance |= rxINSTANCEDONTINSTANCE; res = *pipeData->cacheEntryRef; if(res){ if(pipeData->matPvtData->meshInstanceTestCB) pipeData->matPvtData->meshInstanceTestCB(&pipeData); }else{ pipeData->meshInstance |= rxINSTANCEALL | rxINSTANCEFULLINSTANCE; } if(pipeData->meshInstance & (rxINSTANCEINPLACEINSTANCE| rxINSTANCECONGRUENTINSTANCE| rxINSTANCEFULLINSTANCE) && !PS2AllNodeInstance(&pipeData)) return FALSE; if(rwLLLinkAttached(&res->link)){ rwLinkListRemoveLLLink(&res->link); rwLinkListAddLLLink(&someglobal, &res->link); } } pipeData->matPvtData->bridgeCB(&pipeData); if(pipeData->matPvtData->postMeshCB) pipeData->matPvtData->postMeshCB(&pipeData); mesh++; } if(pvtData->finalizeCB) pvtData->finalizeCB(&pipeData); return TRUE; } RwBool PS2AllPipelineNodeInit(RxPipelineNode *self) { rxNodePS2AllPvtData *pvtData; RwUInt32 *dma; pvtData = (rxNodePS2AllPvtData*)self->privateData; dma = (RwUInt32*)(((RwUInt32)&pvtData->dmabuf + 0xF) & ~0xF); pvtData->lightBufferOffset = vuSDLightOffset; pvtData->lightBufferSize = vuSDBlockHigh-vuSDLightOffset; dma[0] = 0; dma[1] = 0; dma[2] = 0x01000404; // STCYCL dma[3] = 0x6C010000 | pvtData->lightBufferOffset+4; dma[4] = 0; // this marks the end of the light buffer dma[5] = 0; dma[6] = 0; dma[7] = 0; pvtData->groupPipe = NULL; pvtData->dmaPacket = dma; pvtData->setupCB = NULL; pvtData->finalizeCB = NULL; // TODO pvtData->data1[5] = 3; pvtData->data1[9] = 1; pvtData->data1[12] = 2; pvtData->data1[13] = 0; pvtData->data1[1] = 1; pvtData->data1[2] = 2; pvtData->data1[3] = 1; pvtData->data1[4] = 1; pvtData->data1[6] = 1; pvtData->data1[8] = 0; pvtData->data1[10] = 0; pvtData->data1[11] = 2; } RwChar *_PS2All_csl = "PS2All.csl"; // _PS2All_csl.21 RxNodeDefinition nodePS2AllCSL = { // nodePS2AllCSL.22 _PS2All_csl, { PS2AllNodeBody, NULL, NULL, PS2AllPipelineNodeInit, NULL, NULL, NULL }, { 0, NULL, NULL, 0, NULL }, sizeof(rxNodePS2AllPvtData), rxNODEDEFCONST, 0 }; RxNodeDefinition* RxNodeDefinitionGetPS2All(void) { return &nodePS2AllCSL; } RxPipelineNode* RxPipelineNodePS2AllSetCallBack(RxPipelineNode *self, RxPipelineNodePS2AllCallBackType type, void *func) { rxNodePS2AllPvtData *pvtData; if(self){ pvtData = (rxNodePS2AllPvtData*)self->privateData; if(pvtData){ switch(type){ case rxPS2ALLCALLBACKOBJECTSETUP: if(func == NULL) return NULL; pvtData->setupCB = (RxPipelineNodePS2AllObjectSetupCallBack)func; break; case rxPS2ALLCALLBACKOBJECTFINALIZE: pvtData->finalizeCB = (RxPipelineNodePS2AllObjectFinalizeCallBackfunc; break; default: return NULL; } return self; } } return NULL; } RxPipelineNode* RxPipelineNodePS2AllGroupMeshes(RxPipelineNode *node, RxPipeline *pipe) { rxNodePS2AllPvtData *pvtData; if(node){ pvtData = (rxNodePS2AllPvtData*)node->privateData; if(pvtData){ pvtData->groupPipe = pipe; return node; } } return NULL; } RxPipelineNode* RxPipelineNodePS2AllSetLightBufferOffset(RxPipelineNode *self, RwUInt32 offset) { rxNodePS2AllPvtData *pvtData; if(self){ pvtData = (rxNodePS2AllPvtData*)self->privateData; if(pvtData){ if(offset == 0) offset = vuSDLightOffset; pvtData->lightBufferOffset = offset; pvtData->lightBufferSize = vuSDBlockHigh-offset; pvtData->dmaPacket[0] = 0; pvtData->dmaPacket[1] = 0; pvtData->dmaPacket[2] = 0x01000404; // STCYCL pvtData->dmaPacket[3] = 0x6C010000 | pvtData->lightBufferOffset+4; return self; } } return NULL; }