diff --git a/src/ps2.cpp b/src/ps2.cpp index 753d9e4..576de52 100644 --- a/src/ps2.cpp +++ b/src/ps2.cpp @@ -45,11 +45,13 @@ ReadNativeData(Stream *stream, int32, void *object, int32, int32) uint32 buf[2]; stream->read(buf, 8); instance->dataSize = buf[0]; - instance->noRefChain = buf[1]; + instance->arePointersFixed = buf[1]; // TODO: force alignment instance->data = new uint8[instance->dataSize]; - uint64 a = (uint64)instance->data ; +#ifdef RW_PS2 + uint32 a = (uint32)instance->data; assert(a % 0x10 == 0); +#endif stream->read(instance->data, instance->dataSize); } } @@ -65,9 +67,11 @@ WriteNativeData(Stream *stream, int32 len, void *object, int32, int32) InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData; for(uint32 i = 0; i < header->numMeshes; i++){ InstanceData *instance = &header->instanceMeshes[i]; + if(instance->arePointersFixed == 2) + unfixDmaOffsets(instance); uint32 buf[2]; buf[0] = instance->dataSize; - buf[1] = instance->noRefChain; + buf[1] = instance->arePointersFixed; stream->write(buf, 8); stream->write(instance->data, instance->dataSize); } @@ -100,5 +104,81 @@ registerNativeDataPlugin(void) (StreamGetSize)GetSizeNativeData); } +#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 + tag[1] = base + tag[1]*0x10; + 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) +{ +#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 + tag[1] = (tag[1] - base)/0x10; + 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 +} + } } diff --git a/src/rwps2.h b/src/rwps2.h index 5fa41b4..81d50e8 100644 --- a/src/rwps2.h +++ b/src/rwps2.h @@ -3,7 +3,11 @@ namespace Ps2 { struct InstanceData { - uint32 noRefChain; + // 0 - addresses in ref tags need fixing + // 1 - no ref tags, so no fixing + // set by the program: + // 2 - ref tags are fixed, need to unfix before stream write + uint32 arePointersFixed; uint32 dataSize; uint8 *data; Material *material; @@ -21,5 +25,9 @@ void WriteNativeData(Stream *stream, int32 len, void *object, int32, int32); int32 GetSizeNativeData(void *object, int32, int32); void registerNativeDataPlugin(void); +// only RW_PS2 +void fixDmaOffsets(InstanceData *inst); +void unfixDmaOffsets(InstanceData *inst); + } }