librw/src/ps2.cpp

185 lines
4.2 KiB
C++
Raw Normal View History

2014-12-20 18:24:08 +01:00
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <new>
2014-12-20 18:24:08 +01:00
#include "rwbase.h"
#include "rwplugin.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;
namespace Rw {
2014-12-30 17:39:39 +01:00
namespace Ps2 {
2014-12-20 18:24:08 +01:00
2014-12-20 20:18:41 +01:00
void*
2014-12-30 17:39:39 +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
2014-12-30 17:39:39 +01:00
ReadNativeData(Stream *stream, int32, void *object, int32, int32)
2014-12-20 18:24:08 +01:00
{
Geometry *geometry = (Geometry*)object;
assert(FindChunk(stream, ID_STRUCT, NULL, NULL));
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;
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];
stream->read(buf, 8);
2014-12-20 18:24:08 +01:00
instance->dataSize = buf[0];
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];
#ifdef RW_PS2
uint32 a = (uint32)instance->data;
2014-12-30 17:39:39 +01:00
assert(a % 0x10 == 0);
#endif
stream->read(instance->data, instance->dataSize);
2014-12-20 18:24:08 +01:00
}
}
void
2014-12-30 17:39:39 +01:00
WriteNativeData(Stream *stream, int32 len, void *object, int32, int32)
2014-12-20 18:24:08 +01:00
{
Geometry *geometry = (Geometry*)object;
WriteChunkHeader(stream, ID_STRUCT, len-12);
2014-12-20 20:18:41 +01:00
assert(geometry->instData->platform == PLATFORM_PS2);
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];
if(instance->arePointersFixed == 2)
unfixDmaOffsets(instance);
2014-12-20 18:24:08 +01:00
uint32 buf[2];
buf[0] = instance->dataSize;
buf[1] = instance->arePointersFixed;
stream->write(buf, 8);
stream->write(instance->data, instance->dataSize);
2014-12-20 18:24:08 +01:00
}
}
int32
2014-12-30 17:39:39 +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
registerNativeDataPlugin(void)
{
Geometry::registerPlugin(0, ID_NATIVEDATA,
NULL, DestroyNativeData, NULL);
Geometry::registerPluginStream(ID_NATIVEDATA,
(StreamRead)ReadNativeData,
(StreamWrite)WriteNativeData,
(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
}
2014-12-30 17:39:39 +01:00
}
2014-12-20 18:24:08 +01:00
}