2014-12-20 18:24:08 +01:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cassert>
|
|
|
|
|
2014-12-27 23:18:10 +01:00
|
|
|
#include <new>
|
2014-12-20 18:24:08 +01:00
|
|
|
|
|
|
|
#include "rwbase.h"
|
|
|
|
#include "rwplugin.h"
|
2015-07-11 23:48:11 +02:00
|
|
|
#include "rwpipeline.h"
|
2014-12-23 15:59:14 +01:00
|
|
|
#include "rwobjects.h"
|
2014-12-20 18:24:08 +01:00
|
|
|
#include "rwps2.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
namespace rw {
|
|
|
|
namespace ps2 {
|
2014-12-20 18:24:08 +01:00
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline *defaultObjPipe;
|
|
|
|
MatPipeline *defaultMatPipe;
|
|
|
|
|
2014-12-20 20:18:41 +01:00
|
|
|
void*
|
2015-01-25 22:27:03 +01:00
|
|
|
destroyNativeData(void *object, int32, int32)
|
2014-12-20 20:18:41 +01:00
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
assert(geometry->instData->platform == PLATFORM_PS2);
|
2014-12-30 17:39:39 +01:00
|
|
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
2014-12-20 20:18:41 +01:00
|
|
|
for(uint32 i = 0; i < header->numMeshes; i++)
|
|
|
|
delete[] header->instanceMeshes[i].data;
|
|
|
|
delete[] header->instanceMeshes;
|
|
|
|
delete header;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
2014-12-20 18:24:08 +01:00
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
readNativeData(Stream *stream, int32, void *object, int32, int32)
|
2014-12-20 18:24:08 +01:00
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
2015-01-25 22:27:03 +01:00
|
|
|
assert(findChunk(stream, ID_STRUCT, NULL, NULL));
|
2014-12-27 23:18:10 +01:00
|
|
|
assert(stream->readU32() == PLATFORM_PS2);
|
2014-12-30 17:39:39 +01:00
|
|
|
InstanceDataHeader *header = new InstanceDataHeader;
|
2014-12-20 18:24:08 +01:00
|
|
|
geometry->instData = header;
|
2014-12-23 11:29:37 +01:00
|
|
|
header->platform = PLATFORM_PS2;
|
2014-12-20 18:24:08 +01:00
|
|
|
assert(geometry->meshHeader != NULL);
|
|
|
|
header->numMeshes = geometry->meshHeader->numMeshes;
|
2014-12-30 17:39:39 +01:00
|
|
|
header->instanceMeshes = new InstanceData[header->numMeshes];
|
2014-12-20 18:24:08 +01:00
|
|
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
2014-12-30 17:39:39 +01:00
|
|
|
InstanceData *instance = &header->instanceMeshes[i];
|
2014-12-20 18:24:08 +01:00
|
|
|
uint32 buf[2];
|
2014-12-27 23:18:10 +01:00
|
|
|
stream->read(buf, 8);
|
2014-12-20 18:24:08 +01:00
|
|
|
instance->dataSize = buf[0];
|
2014-12-30 19:30:13 +01:00
|
|
|
instance->arePointersFixed = buf[1];
|
2014-12-30 17:39:39 +01:00
|
|
|
// TODO: force alignment
|
2014-12-20 18:24:08 +01:00
|
|
|
instance->data = new uint8[instance->dataSize];
|
2014-12-30 19:30:13 +01:00
|
|
|
#ifdef RW_PS2
|
|
|
|
uint32 a = (uint32)instance->data;
|
2014-12-30 17:39:39 +01:00
|
|
|
assert(a % 0x10 == 0);
|
2014-12-30 19:30:13 +01:00
|
|
|
#endif
|
2014-12-27 23:18:10 +01:00
|
|
|
stream->read(instance->data, instance->dataSize);
|
2015-01-06 23:17:05 +01:00
|
|
|
// sizedebug(instance);
|
2014-12-20 18:24:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
writeNativeData(Stream *stream, int32 len, void *object, int32, int32)
|
2014-12-20 18:24:08 +01:00
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
2015-01-25 22:27:03 +01:00
|
|
|
writeChunkHeader(stream, ID_STRUCT, len-12);
|
2014-12-20 20:18:41 +01:00
|
|
|
assert(geometry->instData->platform == PLATFORM_PS2);
|
2014-12-27 23:18:10 +01:00
|
|
|
stream->writeU32(PLATFORM_PS2);
|
2014-12-20 18:24:08 +01:00
|
|
|
assert(geometry->instData != NULL);
|
2014-12-30 17:39:39 +01:00
|
|
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
2014-12-20 18:24:08 +01:00
|
|
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
2014-12-30 17:39:39 +01:00
|
|
|
InstanceData *instance = &header->instanceMeshes[i];
|
2014-12-30 19:30:13 +01:00
|
|
|
if(instance->arePointersFixed == 2)
|
|
|
|
unfixDmaOffsets(instance);
|
2014-12-20 18:24:08 +01:00
|
|
|
uint32 buf[2];
|
|
|
|
buf[0] = instance->dataSize;
|
2014-12-30 19:30:13 +01:00
|
|
|
buf[1] = instance->arePointersFixed;
|
2014-12-27 23:18:10 +01:00
|
|
|
stream->write(buf, 8);
|
|
|
|
stream->write(instance->data, instance->dataSize);
|
2014-12-20 18:24:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32
|
2015-01-25 22:27:03 +01:00
|
|
|
getSizeNativeData(void *object, int32, int32)
|
2014-12-20 18:24:08 +01:00
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
int32 size = 16;
|
2014-12-20 20:18:41 +01:00
|
|
|
assert(geometry->instData->platform == PLATFORM_PS2);
|
2014-12-20 18:24:08 +01:00
|
|
|
assert(geometry->instData != NULL);
|
2014-12-30 17:39:39 +01:00
|
|
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
2014-12-20 18:24:08 +01:00
|
|
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
2014-12-30 17:39:39 +01:00
|
|
|
InstanceData *instance = &header->instanceMeshes[i];
|
2014-12-20 18:24:08 +01:00
|
|
|
size += 8;
|
|
|
|
size += instance->dataSize;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2014-12-30 17:39:39 +01:00
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
registerNativeDataPlugin(void)
|
2014-12-30 17:39:39 +01:00
|
|
|
{
|
|
|
|
Geometry::registerPlugin(0, ID_NATIVEDATA,
|
2015-01-25 22:27:03 +01:00
|
|
|
NULL, destroyNativeData, NULL);
|
2014-12-30 17:39:39 +01:00
|
|
|
Geometry::registerPluginStream(ID_NATIVEDATA,
|
2015-01-25 22:27:03 +01:00
|
|
|
readNativeData,
|
|
|
|
writeNativeData,
|
|
|
|
getSizeNativeData);
|
2014-12-30 17:39:39 +01:00
|
|
|
}
|
|
|
|
|
2014-12-30 19:30:13 +01:00
|
|
|
#ifdef RW_PS2
|
|
|
|
void
|
|
|
|
fixDmaOffsets(InstanceData *inst)
|
|
|
|
{
|
|
|
|
if(inst->arePointersFixed)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint32 base = (uint32)inst->data;
|
|
|
|
uint32 *tag = (uint32*)inst->data;
|
|
|
|
for(;;){
|
|
|
|
switch(tag[0]&0x70000000){
|
|
|
|
// DMAcnt
|
|
|
|
case 0x10000000:
|
|
|
|
// no need to fix
|
|
|
|
tag += (1+(tag[0]&0xFFFF))*4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAref
|
|
|
|
case 0x30000000:
|
|
|
|
// fix address and jump to next
|
2015-07-12 22:57:05 +02:00
|
|
|
tag[1] = base + tag[1]<<4;
|
2014-12-30 19:30:13 +01:00
|
|
|
tag += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAret
|
|
|
|
case 0x60000000:
|
|
|
|
// we're done
|
|
|
|
inst->arePointersFixed = 2;
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "error: unknown DMAtag %X\n", tag[0]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
unfixDmaOffsets(InstanceData *inst)
|
|
|
|
{
|
2015-07-11 23:48:11 +02:00
|
|
|
(void)inst;
|
2014-12-30 19:30:13 +01:00
|
|
|
#ifdef RW_PS2
|
|
|
|
if(inst->arePointersFixed != 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
uint32 base = (uint32)inst->data;
|
|
|
|
uint32 *tag = (uint32*)inst->data;
|
|
|
|
for(;;){
|
|
|
|
switch(tag[0]&0x70000000){
|
|
|
|
// DMAcnt
|
|
|
|
case 0x10000000:
|
|
|
|
// no need to unfix
|
|
|
|
tag += (1+(tag[0]&0xFFFF))*4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAref
|
|
|
|
case 0x30000000:
|
|
|
|
// unfix address and jump to next
|
2015-07-12 22:57:05 +02:00
|
|
|
tag[1] = (tag[1] - base)>>4;
|
2014-12-30 19:30:13 +01:00
|
|
|
tag += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAret
|
|
|
|
case 0x60000000:
|
|
|
|
// we're done
|
|
|
|
inst->arePointersFixed = 0;
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "error: unknown DMAtag %X\n", tag[0]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-07-11 23:48:11 +02:00
|
|
|
// Pipeline
|
|
|
|
|
|
|
|
enum PS2Attribs {
|
|
|
|
AT_V2_32 = 0x64000000,
|
|
|
|
AT_V2_16 = 0x65000000,
|
|
|
|
AT_V2_8 = 0x66000000,
|
|
|
|
AT_V3_32 = 0x68000000,
|
|
|
|
AT_V3_16 = 0x69000000,
|
|
|
|
AT_V3_8 = 0x6A000000,
|
|
|
|
AT_V4_32 = 0x6C000000,
|
|
|
|
AT_V4_16 = 0x6D000000,
|
|
|
|
AT_V4_8 = 0x6E000000,
|
|
|
|
AT_UNSGN = 0x00004000,
|
|
|
|
|
|
|
|
AT_RW = 0x6
|
|
|
|
};
|
|
|
|
|
|
|
|
enum PS2AttibTypes {
|
|
|
|
AT_XYZ = 0,
|
|
|
|
AT_UV = 1,
|
2015-07-12 22:57:05 +02:00
|
|
|
AT_RGBA = 2,
|
|
|
|
AT_NORMAL = 3
|
2015-07-11 23:48:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
PipeAttribute attribXYZ = {
|
|
|
|
"XYZ",
|
|
|
|
AT_V3_32
|
|
|
|
};
|
|
|
|
|
|
|
|
PipeAttribute attribUV = {
|
|
|
|
"UV",
|
|
|
|
AT_V2_32
|
|
|
|
};
|
|
|
|
|
|
|
|
PipeAttribute attribUV2 = {
|
|
|
|
"UV2",
|
|
|
|
AT_V4_32
|
|
|
|
};
|
|
|
|
|
|
|
|
PipeAttribute attribRGBA = {
|
|
|
|
"RGBA",
|
|
|
|
AT_V4_8 | AT_UNSGN
|
|
|
|
};
|
|
|
|
|
|
|
|
PipeAttribute attribNormal = {
|
|
|
|
"Normal",
|
|
|
|
AT_V3_8 // RW has V4_8 but uses V3_8, wtf?
|
|
|
|
};
|
|
|
|
|
|
|
|
PipeAttribute attribWeights = {
|
|
|
|
"Weights",
|
|
|
|
AT_V4_32 | AT_RW
|
|
|
|
};
|
|
|
|
|
2015-07-12 22:57:05 +02:00
|
|
|
static uint32
|
|
|
|
attribSize(uint32 unpack)
|
|
|
|
{
|
|
|
|
static uint32 size[] = { 32, 16, 8, 16 };
|
|
|
|
return ((unpack>>26 & 3)+1)*size[unpack>>24 & 3]/8;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define QWC(x) (((x)+0xF)>>4)
|
|
|
|
|
|
|
|
static uint32
|
2015-08-01 23:03:10 +02:00
|
|
|
getBatchSize(MatPipeline *pipe, uint32 vertCount)
|
2015-07-12 22:57:05 +02:00
|
|
|
{
|
|
|
|
PipeAttribute *a;
|
|
|
|
uint32 size = 1;
|
|
|
|
for(uint i = 0; i < nelem(pipe->attribs); i++)
|
|
|
|
if((a = pipe->attribs[i]) && (a->attrib & AT_RW) == 0){
|
|
|
|
size++;
|
|
|
|
size += QWC(vertCount*attribSize(a->attrib));
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32*
|
|
|
|
instanceXYZ(uint32 *p, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
|
|
|
{
|
|
|
|
uint16 j;
|
|
|
|
uint32 *d = (uint32*)g->morphTargets[0].vertices;
|
|
|
|
for(uint32 i = idx; i < idx+n; i++){
|
|
|
|
j = m->indices[i];
|
|
|
|
*p++ = d[j*3+0];
|
|
|
|
*p++ = d[j*3+1];
|
|
|
|
*p++ = d[j*3+2];
|
|
|
|
}
|
|
|
|
while((uintptr)p % 0x10)
|
|
|
|
*p++ = 0;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32*
|
|
|
|
instanceUV(uint32 *p, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
|
|
|
{
|
|
|
|
uint16 j;
|
|
|
|
uint32 *d = (uint32*)g->texCoords[0];
|
|
|
|
if((g->geoflags & Geometry::TEXTURED) ||
|
|
|
|
(g->geoflags & Geometry::TEXTURED2))
|
|
|
|
for(uint32 i = idx; i < idx+n; i++){
|
|
|
|
j = m->indices[i];
|
|
|
|
*p++ = d[j*2+0];
|
|
|
|
*p++ = d[j*2+1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for(uint32 i = idx; i < idx+n; i++){
|
|
|
|
*p++ = 0;
|
|
|
|
*p++ = 0;
|
|
|
|
}
|
|
|
|
while((uintptr)p % 0x10)
|
|
|
|
*p++ = 0;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32*
|
|
|
|
instanceRGBA(uint32 *p, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
|
|
|
{
|
|
|
|
uint16 j;
|
|
|
|
uint32 *d = (uint32*)g->colors;
|
|
|
|
if((g->geoflags & Geometry::PRELIT))
|
|
|
|
for(uint32 i = idx; i < idx+n; i++){
|
|
|
|
j = m->indices[i];
|
|
|
|
*p++ = d[j];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for(uint32 i = idx; i < idx+n; i++)
|
|
|
|
*p++ = 0xFF000000;
|
|
|
|
while((uintptr)p % 0x10)
|
|
|
|
*p++ = 0;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32*
|
|
|
|
instanceNormal(uint32 *wp, Geometry *g, Mesh *m, uint32 idx, uint32 n)
|
|
|
|
{
|
|
|
|
uint16 j;
|
|
|
|
float *d = g->morphTargets[0].normals;
|
|
|
|
uint8 *p = (uint8*)wp;
|
|
|
|
if((g->geoflags & Geometry::NORMALS))
|
|
|
|
for(uint32 i = idx; i < idx+n; i++){
|
|
|
|
j = m->indices[i];
|
|
|
|
*p++ = d[j*3+0]*127.0f;
|
|
|
|
*p++ = d[j*3+1]*127.0f;
|
|
|
|
*p++ = d[j*3+2]*127.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for(uint32 i = idx; i < idx+n; i++){
|
|
|
|
*p++ = 0;
|
|
|
|
*p++ = 0;
|
|
|
|
*p++ = 0;
|
|
|
|
}
|
|
|
|
while((uintptr)p % 0x10)
|
|
|
|
*p++ = 0;
|
|
|
|
return (uint32*)p;
|
|
|
|
}
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
MatPipeline::MatPipeline(uint32 platform)
|
|
|
|
: rw::Pipeline(platform), instanceCB(NULL)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < 10; i++)
|
|
|
|
this->attribs[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MatPipeline::dump(void)
|
|
|
|
{
|
|
|
|
if(this->platform != PLATFORM_PS2)
|
|
|
|
return;
|
|
|
|
PipeAttribute *a;
|
|
|
|
for(uint i = 0; i < nelem(this->attribs); i++){
|
|
|
|
a = this->attribs[i];
|
|
|
|
if(a)
|
|
|
|
printf("%d %s: %x\n", i, a->name, a->attrib);
|
|
|
|
}
|
|
|
|
printf("stride: %x\n", this->inputStride);
|
|
|
|
printf("triSCount: %x\n", this->triStripCount);
|
|
|
|
printf("triLCount: %x\n", this->triListCount);
|
|
|
|
printf("vifOffset: %x\n", this->vifOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MatPipeline::setTriBufferSizes(uint32 inputStride, uint32 stripCount)
|
|
|
|
{
|
|
|
|
this->inputStride = inputStride;
|
|
|
|
this->triListCount = stripCount/12*12;
|
|
|
|
PipeAttribute *a;
|
|
|
|
for(uint i = 0; i < nelem(this->attribs); i++){
|
|
|
|
a = this->attribs[i];
|
|
|
|
if(a && a->attrib & AT_RW)
|
|
|
|
goto brokenout;
|
|
|
|
}
|
|
|
|
this->triStripCount = stripCount/4*4;
|
|
|
|
return;
|
|
|
|
brokenout:
|
|
|
|
this->triStripCount = (stripCount-2)/4*4+2;
|
|
|
|
}
|
|
|
|
|
2015-07-12 22:57:05 +02:00
|
|
|
uint32 markcnt = 0xf790;
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
void
|
|
|
|
MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m)
|
2015-07-12 22:57:05 +02:00
|
|
|
{
|
|
|
|
PipeAttribute *a;
|
|
|
|
uint32 numAttribs = 0;
|
|
|
|
uint32 numBrokenAttribs = 0;
|
2015-08-02 19:31:01 +02:00
|
|
|
for(uint i = 0; i < nelem(this->attribs); i++)
|
|
|
|
if(a = this->attribs[i])
|
2015-07-12 22:57:05 +02:00
|
|
|
if(a->attrib & AT_RW)
|
|
|
|
numBrokenAttribs++;
|
|
|
|
else
|
|
|
|
numAttribs++;
|
|
|
|
uint32 numBatches = 0;
|
|
|
|
uint32 totalVerts = 0;
|
|
|
|
uint32 batchVertCount, lastBatchVertCount;
|
|
|
|
if(g->meshHeader->flags == 1){ // tristrip
|
2015-08-02 19:31:01 +02:00
|
|
|
for(uint i = 0; i < m->numIndices; i += this->triStripCount-2){
|
2015-07-12 22:57:05 +02:00
|
|
|
numBatches++;
|
2015-08-02 19:31:01 +02:00
|
|
|
totalVerts += m->numIndices-i < this->triStripCount ?
|
|
|
|
m->numIndices-i : this->triStripCount;
|
2015-07-12 22:57:05 +02:00
|
|
|
}
|
2015-08-02 19:31:01 +02:00
|
|
|
batchVertCount = this->triStripCount;
|
|
|
|
lastBatchVertCount = totalVerts%this->triStripCount;
|
2015-08-01 23:03:10 +02:00
|
|
|
}else{ // trilist
|
2015-08-02 19:31:01 +02:00
|
|
|
numBatches = (m->numIndices+this->triListCount-1) /
|
|
|
|
this->triListCount;
|
2015-07-12 22:57:05 +02:00
|
|
|
totalVerts = m->numIndices;
|
2015-08-02 19:31:01 +02:00
|
|
|
batchVertCount = this->triListCount;
|
|
|
|
lastBatchVertCount = totalVerts%this->triListCount;
|
2015-07-12 22:57:05 +02:00
|
|
|
}
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
uint32 batchSize = getBatchSize(this, batchVertCount);
|
|
|
|
uint32 lastBatchSize = getBatchSize(this, lastBatchVertCount);
|
2015-07-12 22:57:05 +02:00
|
|
|
uint32 size = 0;
|
|
|
|
if(numBrokenAttribs == 0)
|
|
|
|
size = 1 + batchSize*(numBatches-1) + lastBatchSize;
|
|
|
|
else
|
|
|
|
size = 2*numBatches +
|
|
|
|
(1+batchSize)*(numBatches-1) + 1+lastBatchSize;
|
|
|
|
|
|
|
|
/* figure out size and addresses of broken out sections */
|
2015-08-02 19:31:01 +02:00
|
|
|
uint32 attribPos[nelem(this->attribs)];
|
2015-07-12 22:57:05 +02:00
|
|
|
uint32 size2 = 0;
|
2015-08-02 19:31:01 +02:00
|
|
|
for(uint i = 0; i < nelem(this->attribs); i++)
|
|
|
|
if((a = this->attribs[i]) && a->attrib & AT_RW){
|
2015-07-12 22:57:05 +02:00
|
|
|
attribPos[i] = size2 + size;
|
|
|
|
size2 += QWC(m->numIndices*attribSize(a->attrib));
|
|
|
|
}
|
|
|
|
|
|
|
|
inst->dataSize = (size+size2)<<4;
|
|
|
|
inst->arePointersFixed = numBrokenAttribs == 0;
|
|
|
|
// TODO: force alignment
|
|
|
|
inst->data = new uint8[inst->dataSize];
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
/* make array of addresses of broken out sections */
|
|
|
|
uint8 *datap[nelem(this->attribs)];
|
|
|
|
uint8 **dp = datap;
|
|
|
|
for(uint i = 0; i < nelem(this->attribs); i++)
|
|
|
|
if((a = this->attribs[i]) && a->attrib & AT_RW)
|
|
|
|
*dp++ = inst->data + attribPos[i]*0x10;
|
|
|
|
|
2015-07-12 22:57:05 +02:00
|
|
|
uint32 idx = 0;
|
|
|
|
uint32 *p = (uint32*)inst->data;
|
|
|
|
if(numBrokenAttribs == 0){
|
|
|
|
*p++ = 0x60000000 | size-1;
|
|
|
|
*p++ = 0;
|
|
|
|
*p++ = 0x11000000; // FLUSH
|
|
|
|
*p++ = 0x06000000; // MSKPATH3; SA: FLUSH
|
|
|
|
}
|
|
|
|
for(uint32 j = 0; j < numBatches; j++){
|
|
|
|
uint32 nverts, bsize;
|
|
|
|
if(j < numBatches-1){
|
|
|
|
bsize = batchSize;
|
|
|
|
nverts = batchVertCount;
|
|
|
|
}else{
|
|
|
|
bsize = lastBatchSize;
|
|
|
|
nverts = lastBatchVertCount;
|
|
|
|
}
|
2015-08-02 19:31:01 +02:00
|
|
|
for(uint i = 0; i < nelem(this->attribs); i++)
|
|
|
|
if((a = this->attribs[i]) && a->attrib & AT_RW){
|
2015-07-12 22:57:05 +02:00
|
|
|
uint32 atsz = attribSize(a->attrib);
|
|
|
|
*p++ = 0x30000000 | QWC(nverts*atsz);
|
|
|
|
*p++ = attribPos[i];
|
|
|
|
*p++ = 0x01000100 |
|
2015-08-02 19:31:01 +02:00
|
|
|
this->inputStride; // STCYCL
|
2015-07-12 22:57:05 +02:00
|
|
|
*p++ = (a->attrib&0xFF004000)
|
|
|
|
| 0x8000 | nverts << 16 | i; // UNPACK
|
|
|
|
|
|
|
|
*p++ = 0x10000000;
|
|
|
|
*p++ = 0x0;
|
|
|
|
*p++ = 0x0;
|
|
|
|
*p++ = 0x0;
|
|
|
|
|
|
|
|
attribPos[i] += g->meshHeader->flags == 1 ?
|
|
|
|
QWC((batchVertCount-2)*atsz) :
|
|
|
|
QWC(batchVertCount*atsz);
|
|
|
|
}
|
|
|
|
if(numBrokenAttribs){
|
|
|
|
*p++ = (j < numBatches-1 ? 0x10000000 : 0x60000000) |
|
|
|
|
bsize;
|
|
|
|
*p++ = 0x0;
|
|
|
|
*p++ = 0x0;
|
|
|
|
*p++ = 0x0;
|
|
|
|
}
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
for(uint i = 0; i < nelem(this->attribs); i++)
|
|
|
|
if((a = this->attribs[i]) && (a->attrib & AT_RW) == 0){
|
2015-07-12 22:57:05 +02:00
|
|
|
*p++ = 0x07000000 | markcnt++; // MARK (SA: NOP)
|
|
|
|
*p++ = 0x05000000; // STMOD
|
|
|
|
*p++ = 0x01000100 |
|
2015-08-02 19:31:01 +02:00
|
|
|
this->inputStride; // STCYCL
|
2015-07-12 22:57:05 +02:00
|
|
|
*p++ = (a->attrib&0xFF004000)
|
|
|
|
| 0x8000 | nverts << 16 | i; // UNPACK
|
|
|
|
|
|
|
|
switch(i){
|
|
|
|
case 0:
|
|
|
|
p = instanceXYZ(p, g, m, idx, nverts);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
p = instanceUV(p, g, m, idx, nverts);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
p = instanceRGBA(p, g, m, idx, nverts);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
p = instanceNormal(p,g, m, idx, nverts);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
idx += g->meshHeader->flags == 1
|
|
|
|
? batchVertCount-2 : batchVertCount;
|
|
|
|
|
|
|
|
*p++ = 0x04000000 | nverts; // ITOP
|
|
|
|
*p++ = j == 0 ? 0x15000000 : 0x17000000;
|
|
|
|
if(j < numBatches-1){
|
|
|
|
*p++ = 0x0;
|
|
|
|
*p++ = 0x0;
|
|
|
|
}else{
|
|
|
|
*p++ = 0x11000000; // FLUSH
|
|
|
|
*p++ = 0x06000000; // MSKPATH3; SA: FLUSH
|
|
|
|
}
|
|
|
|
}
|
2015-08-02 19:31:01 +02:00
|
|
|
|
|
|
|
if(instanceCB)
|
|
|
|
instanceCB(this, g, m, datap, numBrokenAttribs);
|
2015-07-12 22:57:05 +02:00
|
|
|
}
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline::ObjPipeline(uint32 platform)
|
2015-08-02 19:31:01 +02:00
|
|
|
: rw::ObjPipeline(platform), groupPipeline(NULL) { }
|
2015-08-01 23:03:10 +02:00
|
|
|
|
2015-07-12 22:57:05 +02:00
|
|
|
void
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline::instance(Atomic *atomic)
|
2015-07-12 22:57:05 +02:00
|
|
|
{
|
|
|
|
Geometry *geometry = atomic->geometry;
|
2015-08-01 23:03:10 +02:00
|
|
|
if(geometry->geoflags & Geometry::NATIVE)
|
|
|
|
return;
|
2015-07-12 22:57:05 +02:00
|
|
|
InstanceDataHeader *header = new InstanceDataHeader;
|
|
|
|
geometry->instData = header;
|
|
|
|
header->platform = PLATFORM_PS2;
|
|
|
|
assert(geometry->meshHeader != NULL);
|
|
|
|
header->numMeshes = geometry->meshHeader->numMeshes;
|
|
|
|
header->instanceMeshes = new InstanceData[header->numMeshes];
|
|
|
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
|
|
|
Mesh *mesh = &geometry->meshHeader->mesh[i];
|
|
|
|
InstanceData *instance = &header->instanceMeshes[i];
|
2015-08-01 23:03:10 +02:00
|
|
|
|
|
|
|
MatPipeline *m;
|
|
|
|
m = this->groupPipeline ?
|
2015-08-02 19:31:01 +02:00
|
|
|
this->groupPipeline :
|
2015-08-01 23:03:10 +02:00
|
|
|
(MatPipeline*)mesh->material->pipeline;
|
|
|
|
if(m == NULL)
|
|
|
|
m = defaultMatPipe;
|
2015-08-02 19:31:01 +02:00
|
|
|
m->instance(geometry, instance, mesh);
|
2015-07-12 22:57:05 +02:00
|
|
|
}
|
|
|
|
geometry->geoflags |= Geometry::NATIVE;
|
|
|
|
}
|
|
|
|
|
2015-07-13 15:01:31 +02:00
|
|
|
void
|
|
|
|
printVertCounts(InstanceData *inst, int flag)
|
|
|
|
{
|
|
|
|
uint32 *d = (uint32*)inst->data;
|
|
|
|
int stride;
|
|
|
|
if(inst->arePointersFixed){
|
|
|
|
d += 4;
|
|
|
|
while(d[3]&0x60000000){ // skip UNPACKs
|
|
|
|
stride = d[2]&0xFF;
|
|
|
|
d += 4 + 4*QWC(attribSize(d[3])*((d[3]>>16)&0xFF));
|
|
|
|
}
|
|
|
|
if(d[2] == 0)
|
|
|
|
printf("ITOP %x %d (%d)\n", *d, stride, flag);
|
|
|
|
}else{
|
|
|
|
while((*d&0x70000000) == 0x30000000){
|
|
|
|
stride = d[2]&0xFF;
|
|
|
|
d += 8;
|
|
|
|
}
|
|
|
|
if((*d&0x70000000) == 0x10000000){
|
|
|
|
d += (*d&0xFFFF)*4;
|
|
|
|
printf("ITOP %x %d (%d)\n", *d, stride, flag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-12 22:57:05 +02:00
|
|
|
// Only a dummy right now
|
|
|
|
void
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline::uninstance(Atomic *atomic)
|
2015-07-12 22:57:05 +02:00
|
|
|
{
|
|
|
|
Geometry *geometry = atomic->geometry;
|
|
|
|
assert(geometry->instData->platform == PLATFORM_PS2);
|
|
|
|
assert(geometry->instData != NULL);
|
|
|
|
InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
|
|
|
|
for(uint32 i = 0; i < header->numMeshes; i++){
|
|
|
|
Mesh *mesh = &geometry->meshHeader->mesh[i];
|
|
|
|
InstanceData *instance = &header->instanceMeshes[i];
|
2015-07-13 15:01:31 +02:00
|
|
|
// printf("numIndices: %d\n", mesh->numIndices);
|
|
|
|
// printDMA(instance);
|
|
|
|
printVertCounts(instance, geometry->meshHeader->flags);
|
2015-07-12 22:57:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-13 15:01:31 +02:00
|
|
|
#undef QWC
|
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline*
|
|
|
|
makeDefaultPipeline(void)
|
2015-07-11 23:48:11 +02:00
|
|
|
{
|
2015-08-01 23:03:10 +02:00
|
|
|
if(defaultMatPipe == NULL){
|
|
|
|
MatPipeline *pipe = new MatPipeline(PLATFORM_PS2);
|
|
|
|
pipe->attribs[AT_XYZ] = &attribXYZ;
|
|
|
|
pipe->attribs[AT_UV] = &attribUV;
|
|
|
|
pipe->attribs[AT_RGBA] = &attribRGBA;
|
|
|
|
pipe->attribs[AT_NORMAL] = &attribNormal;
|
|
|
|
uint32 vertCount = MatPipeline::getVertCount(VU_Lights,4,3,2);
|
|
|
|
pipe->setTriBufferSizes(4, vertCount);
|
|
|
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
|
|
|
defaultMatPipe = pipe;
|
2015-07-11 23:48:11 +02:00
|
|
|
}
|
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
if(defaultObjPipe == NULL){
|
|
|
|
ObjPipeline *opipe = new ObjPipeline(PLATFORM_PS2);
|
|
|
|
defaultObjPipe = opipe;
|
|
|
|
}
|
|
|
|
return defaultObjPipe;
|
2015-07-11 23:48:11 +02:00
|
|
|
}
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
static void skinInstanceCB(MatPipeline*, Geometry*, Mesh*, uint8**, int32);
|
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline*
|
2015-07-11 23:48:11 +02:00
|
|
|
makeSkinPipeline(void)
|
|
|
|
{
|
2015-08-01 23:03:10 +02:00
|
|
|
MatPipeline *pipe = new MatPipeline(PLATFORM_PS2);
|
2015-07-12 22:57:05 +02:00
|
|
|
pipe->pluginID = ID_SKIN;
|
|
|
|
pipe->pluginData = 1;
|
2015-07-11 23:48:11 +02:00
|
|
|
pipe->attribs[AT_XYZ] = &attribXYZ;
|
|
|
|
pipe->attribs[AT_UV] = &attribUV;
|
|
|
|
pipe->attribs[AT_RGBA] = &attribRGBA;
|
|
|
|
pipe->attribs[AT_NORMAL] = &attribNormal;
|
|
|
|
pipe->attribs[AT_NORMAL+1] = &attribWeights;
|
2015-08-01 23:03:10 +02:00
|
|
|
uint32 vertCount = MatPipeline::getVertCount(VU_Lights-0x100, 5, 3, 2);
|
2015-07-13 15:01:31 +02:00
|
|
|
pipe->setTriBufferSizes(5, vertCount);
|
2015-07-11 23:48:11 +02:00
|
|
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
2015-08-02 19:31:01 +02:00
|
|
|
pipe->instanceCB = skinInstanceCB;
|
2015-08-01 23:03:10 +02:00
|
|
|
|
|
|
|
ObjPipeline *opipe = new ObjPipeline(PLATFORM_PS2);
|
|
|
|
opipe->pluginID = ID_SKIN;
|
|
|
|
opipe->pluginData = 1;
|
|
|
|
opipe->groupPipeline = pipe;
|
|
|
|
return opipe;
|
2015-07-11 23:48:11 +02:00
|
|
|
}
|
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline*
|
2015-07-12 22:57:05 +02:00
|
|
|
makeMatFXPipeline(void)
|
|
|
|
{
|
2015-08-01 23:03:10 +02:00
|
|
|
MatPipeline *pipe = new MatPipeline(PLATFORM_PS2);
|
2015-07-12 22:57:05 +02:00
|
|
|
pipe->pluginID = ID_MATFX;
|
|
|
|
pipe->pluginData = 0;
|
|
|
|
pipe->attribs[AT_XYZ] = &attribXYZ;
|
|
|
|
pipe->attribs[AT_UV] = &attribUV;
|
|
|
|
pipe->attribs[AT_RGBA] = &attribRGBA;
|
|
|
|
pipe->attribs[AT_NORMAL] = &attribNormal;
|
2015-08-01 23:03:10 +02:00
|
|
|
uint32 vertCount = MatPipeline::getVertCount(0x3C5, 4, 3, 3);
|
2015-07-13 15:01:31 +02:00
|
|
|
pipe->setTriBufferSizes(4, vertCount);
|
2015-07-12 22:57:05 +02:00
|
|
|
pipe->vifOffset = pipe->inputStride*vertCount;
|
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
ObjPipeline *opipe = new ObjPipeline(PLATFORM_PS2);
|
|
|
|
opipe->pluginID = ID_MATFX;
|
|
|
|
opipe->pluginData = 0;
|
|
|
|
opipe->groupPipeline = pipe;
|
|
|
|
return opipe;
|
2015-07-11 23:48:11 +02:00
|
|
|
}
|
|
|
|
|
2015-01-07 23:06:44 +01:00
|
|
|
// Skin
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
readNativeSkin(Stream *stream, int32, void *object, int32 offset)
|
2015-01-07 23:06:44 +01:00
|
|
|
{
|
|
|
|
uint8 header[4];
|
|
|
|
uint32 vers;
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
2015-01-25 22:27:03 +01:00
|
|
|
assert(findChunk(stream, ID_STRUCT, NULL, &vers));
|
2015-01-07 23:06:44 +01:00
|
|
|
assert(stream->readU32() == PLATFORM_PS2);
|
|
|
|
stream->read(header, 4);
|
|
|
|
Skin *skin = new Skin;
|
|
|
|
*PLUGINOFFSET(Skin*, geometry, offset) = skin;
|
|
|
|
skin->numBones = header[0];
|
|
|
|
|
|
|
|
// both values unused in/before 33002, used in/after 34003
|
|
|
|
skin->numUsedBones = header[1];
|
|
|
|
skin->maxIndex = header[2];
|
|
|
|
|
|
|
|
bool oldFormat = skin->numUsedBones == 0;
|
|
|
|
int32 size = skin->numUsedBones + skin->numBones*64 + 15;
|
|
|
|
uint8 *data = new uint8[size];
|
|
|
|
skin->data = data;
|
|
|
|
skin->indices = NULL;
|
|
|
|
skin->weights = NULL;
|
|
|
|
|
|
|
|
skin->usedBones = NULL;
|
|
|
|
if(skin->numUsedBones){
|
|
|
|
skin->usedBones = data;
|
|
|
|
data += skin->numUsedBones;
|
|
|
|
stream->read(skin->data, skin->numUsedBones);
|
|
|
|
}
|
|
|
|
|
|
|
|
uintptr ptr = (uintptr)data + 15;
|
|
|
|
ptr &= ~0xF;
|
|
|
|
data = (uint8*)ptr;
|
|
|
|
skin->inverseMatrices = NULL;
|
|
|
|
if(skin->numBones){
|
|
|
|
skin->inverseMatrices = (float*)data;
|
|
|
|
stream->read(skin->inverseMatrices, skin->numBones*64);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!oldFormat)
|
|
|
|
// last 3 ints are probably the same as in generic format
|
|
|
|
// TODO: what are the other 4?
|
|
|
|
stream->seek(7*4);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
writeNativeSkin(Stream *stream, int32 len, void *object, int32 offset)
|
2015-01-07 23:06:44 +01:00
|
|
|
{
|
|
|
|
uint8 header[4];
|
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
writeChunkHeader(stream, ID_STRUCT, len-12);
|
2015-01-07 23:06:44 +01:00
|
|
|
stream->writeU32(PLATFORM_PS2);
|
|
|
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
2015-01-25 22:27:03 +01:00
|
|
|
bool oldFormat = version < 0x34003;
|
2015-01-07 23:06:44 +01:00
|
|
|
header[0] = skin->numBones;
|
|
|
|
header[1] = skin->numUsedBones;
|
|
|
|
header[2] = skin->maxIndex;
|
|
|
|
header[3] = 0;
|
|
|
|
if(oldFormat){
|
|
|
|
header[1] = 0;
|
|
|
|
header[2] = 0;
|
|
|
|
}
|
|
|
|
stream->write(header, 4);
|
|
|
|
|
|
|
|
if(!oldFormat)
|
|
|
|
stream->write(skin->usedBones, skin->numUsedBones);
|
|
|
|
stream->write(skin->inverseMatrices, skin->numBones*64);
|
|
|
|
if(!oldFormat){
|
|
|
|
uint32 buffer[7] = { 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
stream->write(buffer, 7*4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32
|
2015-01-25 22:27:03 +01:00
|
|
|
getSizeNativeSkin(void *object, int32 offset)
|
2015-01-07 23:06:44 +01:00
|
|
|
{
|
|
|
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
|
|
|
if(skin == NULL)
|
|
|
|
return -1;
|
|
|
|
int32 size = 12 + 4 + 4 + skin->numBones*64;
|
|
|
|
// not sure which version introduced the new format
|
2015-01-25 22:27:03 +01:00
|
|
|
if(version >= 0x34003)
|
2015-01-07 23:06:44 +01:00
|
|
|
size += skin->numUsedBones + 16 + 12;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2015-08-02 19:31:01 +02:00
|
|
|
static void
|
|
|
|
skinInstanceCB(MatPipeline *pipe, Geometry *g, Mesh *m, uint8 **data, int32 n)
|
|
|
|
{
|
|
|
|
Skin *skin = *PLUGINOFFSET(Skin*, g, skinGlobals.offset);
|
|
|
|
if(skin == NULL || n < 1)
|
|
|
|
return;
|
|
|
|
float *weights = (float*)data[0];
|
|
|
|
uint32 *indices = (uint32*)data[0];
|
|
|
|
uint16 j;
|
|
|
|
for(uint32 i = 0; i < m->numIndices; i++){
|
|
|
|
j = m->indices[i];
|
|
|
|
*weights++ = skin->weights[j*4+0];
|
|
|
|
*indices &= ~0x3FF;
|
|
|
|
*indices++ |= skin->indices[j*4+0] && skin->weights[j*4+0] ?
|
|
|
|
(skin->indices[j*4+0]+1) << 2 : 0;
|
|
|
|
*weights++ = skin->weights[j*4+1];
|
|
|
|
*indices &= ~0x3FF;
|
|
|
|
*indices++ |= skin->indices[j*4+1] && skin->weights[j*4+1] ?
|
|
|
|
(skin->indices[j*4+1]+1) << 2 : 0;
|
|
|
|
*weights++ = skin->weights[j*4+2];
|
|
|
|
*indices &= ~0x3FF;
|
|
|
|
*indices++ |= skin->indices[j*4+2] && skin->weights[j*4+2] ?
|
|
|
|
(skin->indices[j*4+2]+1) << 2 : 0;
|
|
|
|
*weights++ = skin->weights[j*4+3];
|
|
|
|
*indices &= ~0x3FF;
|
|
|
|
*indices++ |= skin->indices[j*4+3] && skin->weights[j*4+3] ?
|
|
|
|
(skin->indices[j*4+3]+1) << 2 : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
|
2015-01-06 23:17:05 +01:00
|
|
|
// ADC
|
|
|
|
|
|
|
|
static void*
|
|
|
|
createADC(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
ADCData *adc = PLUGINOFFSET(ADCData, object, offset);
|
|
|
|
adc->adcFormatted = 0;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
copyADC(void *dst, void *src, int32 offset, int32)
|
|
|
|
{
|
|
|
|
ADCData *dstadc = PLUGINOFFSET(ADCData, dst, offset);
|
|
|
|
ADCData *srcadc = PLUGINOFFSET(ADCData, src, offset);
|
|
|
|
dstadc->adcFormatted = srcadc->adcFormatted;
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2015-01-07 23:06:44 +01:00
|
|
|
// TODO: look at PC SA rccam.dff bloodrb.dff
|
|
|
|
|
2015-01-06 23:17:05 +01:00
|
|
|
static void
|
|
|
|
readADC(Stream *stream, int32, void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
ADCData *adc = PLUGINOFFSET(ADCData, object, offset);
|
|
|
|
stream->seek(12);
|
|
|
|
uint32 x = stream->readU32();
|
|
|
|
assert(x == 0);
|
|
|
|
adc->adcFormatted = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeADC(Stream *stream, int32, void *, int32, int32)
|
|
|
|
{
|
2015-01-25 22:27:03 +01:00
|
|
|
writeChunkHeader(stream, ID_ADC, 4);
|
2015-01-06 23:17:05 +01:00
|
|
|
stream->writeI32(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
getSizeADC(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
ADCData *adc = PLUGINOFFSET(ADCData, object, offset);
|
|
|
|
return adc->adcFormatted ? 16 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
registerADCPlugin(void)
|
2015-01-06 23:17:05 +01:00
|
|
|
{
|
|
|
|
Geometry::registerPlugin(sizeof(ADCData), ID_ADC,
|
|
|
|
createADC, NULL, copyADC);
|
|
|
|
Geometry::registerPluginStream(ID_ADC,
|
2015-01-25 22:27:03 +01:00
|
|
|
readADC,
|
|
|
|
writeADC,
|
|
|
|
getSizeADC);
|
2015-01-06 23:17:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-01 23:03:10 +02:00
|
|
|
// PDS plugin
|
|
|
|
|
|
|
|
static void
|
|
|
|
atomicPDSRights(void *object, int32, int32, uint32 data)
|
|
|
|
{
|
|
|
|
Atomic *a = (Atomic*)object;
|
|
|
|
// TODO: lookup pipeline by data
|
2015-08-02 19:31:01 +02:00
|
|
|
a->pipeline = new ObjPipeline(PLATFORM_PS2);
|
2015-08-01 23:03:10 +02:00
|
|
|
a->pipeline->pluginID = ID_PDS;
|
|
|
|
a->pipeline->pluginData = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
materialPDSRights(void *object, int32, int32, uint32 data)
|
|
|
|
{
|
|
|
|
Material *m = (Material*)object;
|
|
|
|
// TODO: lookup pipeline by data
|
|
|
|
m->pipeline = new Pipeline(PLATFORM_PS2);
|
|
|
|
m->pipeline->pluginID = ID_PDS;
|
|
|
|
m->pipeline->pluginData = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
registerPDSPlugin(void)
|
|
|
|
{
|
|
|
|
Atomic::registerPlugin(0, ID_PDS, NULL, NULL, NULL);
|
|
|
|
Atomic::setStreamRightsCallback(ID_PDS, atomicPDSRights);
|
|
|
|
|
|
|
|
Material::registerPlugin(0, ID_PDS, NULL, NULL, NULL);
|
|
|
|
Material::setStreamRightsCallback(ID_PDS, materialPDSRights);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-06 23:17:05 +01:00
|
|
|
// misc stuff
|
|
|
|
|
2015-07-12 22:57:05 +02:00
|
|
|
void
|
|
|
|
printDMA(InstanceData *inst)
|
|
|
|
{
|
|
|
|
uint32 *tag = (uint32*)inst->data;
|
|
|
|
for(;;){
|
|
|
|
switch(tag[0]&0x70000000){
|
|
|
|
// DMAcnt
|
|
|
|
case 0x10000000:
|
|
|
|
printf("%08x %08x\n", tag[0], tag[1]);
|
|
|
|
tag += (1+(tag[0]&0xFFFF))*4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAref
|
|
|
|
case 0x30000000:
|
|
|
|
printf("%08x %08x\n", tag[0], tag[1]);
|
|
|
|
tag += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAret
|
|
|
|
case 0x60000000:
|
|
|
|
printf("%08x %08x\n", tag[0], tag[1]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-06 23:17:05 +01:00
|
|
|
/* Function to specifically walk geometry chains */
|
|
|
|
void
|
|
|
|
walkDMA(InstanceData *inst, void (*f)(uint32 *data, int32 size))
|
|
|
|
{
|
|
|
|
if(inst->arePointersFixed == 2)
|
|
|
|
return;
|
|
|
|
uint32 *base = (uint32*)inst->data;
|
|
|
|
uint32 *tag = (uint32*)inst->data;
|
|
|
|
for(;;){
|
|
|
|
switch(tag[0]&0x70000000){
|
|
|
|
// DMAcnt
|
|
|
|
case 0x10000000:
|
|
|
|
f(tag+2, 2+(tag[0]&0xFFFF)*4);
|
|
|
|
tag += (1+(tag[0]&0xFFFF))*4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAref
|
2015-07-12 22:57:05 +02:00
|
|
|
case 0x30000000:
|
2015-01-06 23:17:05 +01:00
|
|
|
f(base + tag[1]*4, (tag[0]&0xFFFF)*4);
|
|
|
|
tag += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAret
|
|
|
|
case 0x60000000:
|
|
|
|
f(tag+2, 2+(tag[0]&0xFFFF)*4);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sizedebug(InstanceData *inst)
|
|
|
|
{
|
|
|
|
if(inst->arePointersFixed == 2)
|
|
|
|
return;
|
|
|
|
uint32 *base = (uint32*)inst->data;
|
|
|
|
uint32 *tag = (uint32*)inst->data;
|
|
|
|
uint32 *last = NULL;
|
|
|
|
for(;;){
|
|
|
|
switch(tag[0]&0x70000000){
|
|
|
|
// DMAcnt
|
|
|
|
case 0x10000000:
|
|
|
|
tag += (1+(tag[0]&0xFFFF))*4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAref
|
|
|
|
case 0x30000000:
|
|
|
|
last = base + tag[1]*4 + (tag[0]&0xFFFF)*4;
|
|
|
|
tag += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// DMAret
|
|
|
|
case 0x60000000:
|
|
|
|
tag += (1+(tag[0]&0xFFFF))*4;
|
|
|
|
uint32 diff;
|
|
|
|
if(!last)
|
|
|
|
diff = (uint8*)tag - (uint8*)base;
|
|
|
|
else
|
|
|
|
diff = (uint8*)last - (uint8*)base;
|
|
|
|
printf("%x %x %x\n", inst->dataSize-diff, diff, inst->dataSize);
|
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
|
|
|
printf("unkown DMAtag: %X %X\n", tag[0], tag[1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-30 17:39:39 +01:00
|
|
|
}
|
2014-12-20 18:24:08 +01:00
|
|
|
}
|