2015-01-07 23:06:44 +01:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cassert>
|
2015-06-10 22:52:59 +02:00
|
|
|
|
2015-01-07 23:06:44 +01:00
|
|
|
#include <new>
|
|
|
|
|
|
|
|
#include "rwbase.h"
|
|
|
|
#include "rwplugin.h"
|
2015-07-11 23:48:11 +02:00
|
|
|
#include "rwpipeline.h"
|
2015-01-07 23:06:44 +01:00
|
|
|
#include "rwobjects.h"
|
|
|
|
#include "rwps2.h"
|
|
|
|
#include "rwogl.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
namespace rw {
|
2015-01-07 23:06:44 +01:00
|
|
|
|
2015-01-17 15:15:03 +01:00
|
|
|
//
|
|
|
|
// HAnim
|
|
|
|
//
|
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
int32 hAnimOffset;
|
2015-01-17 15:15:03 +01:00
|
|
|
|
|
|
|
static void*
|
2015-01-20 14:48:18 +01:00
|
|
|
createHAnim(void *object, int32 offset, int32)
|
2015-01-17 15:15:03 +01:00
|
|
|
{
|
|
|
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
|
|
|
hanim->id = -1;
|
|
|
|
hanim->hierarchy = NULL;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
2015-01-20 14:48:18 +01:00
|
|
|
destroyHAnim(void *object, int32 offset, int32)
|
2015-01-17 15:15:03 +01:00
|
|
|
{
|
|
|
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
|
|
|
if(hanim->hierarchy){
|
|
|
|
HAnimHierarchy *hier = hanim->hierarchy;
|
|
|
|
delete[] (uint8*)hier->matricesUnaligned;
|
|
|
|
delete[] hier->nodeInfo;
|
|
|
|
delete hier;
|
|
|
|
}
|
|
|
|
hanim->id = -1;
|
|
|
|
hanim->hierarchy = NULL;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
2015-01-20 14:48:18 +01:00
|
|
|
copyHAnim(void *dst, void *src, int32 offset, int32)
|
2015-01-17 15:15:03 +01:00
|
|
|
{
|
|
|
|
HAnimData *dsthanim = PLUGINOFFSET(HAnimData, dst, offset);
|
|
|
|
HAnimData *srchanim = PLUGINOFFSET(HAnimData, src, offset);
|
|
|
|
dsthanim->id = srchanim->id;
|
|
|
|
// TODO
|
|
|
|
dsthanim->hierarchy = NULL;
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-01-20 14:48:18 +01:00
|
|
|
readHAnim(Stream *stream, int32, void *object, int32 offset, int32)
|
2015-01-17 15:15:03 +01:00
|
|
|
{
|
|
|
|
int32 cnst, numNodes;
|
|
|
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
2015-08-11 20:57:43 +02:00
|
|
|
ver = stream->readI32();
|
|
|
|
if(ver != 0x100){
|
|
|
|
fprintf(stderr, "hanim ver was not 0x100\n");
|
2015-01-17 15:15:03 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
hanim->id = stream->readI32();
|
|
|
|
numNodes = stream->readI32();
|
|
|
|
if(numNodes != 0){
|
|
|
|
HAnimHierarchy *hier = new HAnimHierarchy;
|
|
|
|
hanim->hierarchy = hier;
|
|
|
|
hier->numNodes = numNodes;
|
|
|
|
hier->flags = stream->readI32();
|
|
|
|
hier->maxInterpKeyFrameSize = stream->readI32();
|
|
|
|
hier->parentFrame = (Frame*)object;
|
|
|
|
hier->parentHierarchy = hier;
|
|
|
|
if(hier->flags & 2)
|
|
|
|
hier->matrices = hier->matricesUnaligned = NULL;
|
|
|
|
else{
|
|
|
|
hier->matricesUnaligned =
|
|
|
|
(float*) new uint8[hier->numNodes*64 + 15];
|
|
|
|
hier->matrices =
|
|
|
|
(float*)((uintptr)hier->matricesUnaligned & ~0xF);
|
|
|
|
}
|
|
|
|
hier->nodeInfo = new HAnimNodeInfo[hier->numNodes];
|
|
|
|
for(int32 i = 0; i < hier->numNodes; i++){
|
|
|
|
hier->nodeInfo[i].id = stream->readI32();
|
|
|
|
hier->nodeInfo[i].index = stream->readI32();
|
|
|
|
hier->nodeInfo[i].flags = stream->readI32();
|
|
|
|
hier->nodeInfo[i].frame = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-01-20 14:48:18 +01:00
|
|
|
writeHAnim(Stream *stream, int32, void *object, int32 offset, int32)
|
2015-01-17 15:15:03 +01:00
|
|
|
{
|
|
|
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
|
|
|
stream->writeI32(256);
|
|
|
|
stream->writeI32(hanim->id);
|
|
|
|
if(hanim->hierarchy == NULL){
|
|
|
|
stream->writeI32(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
HAnimHierarchy *hier = hanim->hierarchy;
|
|
|
|
stream->writeI32(hier->numNodes);
|
|
|
|
stream->writeI32(hier->flags);
|
|
|
|
stream->writeI32(hier->maxInterpKeyFrameSize);
|
|
|
|
for(int32 i = 0; i < hier->numNodes; i++){
|
|
|
|
stream->writeI32(hier->nodeInfo[i].id);
|
|
|
|
stream->writeI32(hier->nodeInfo[i].index);
|
|
|
|
stream->writeI32(hier->nodeInfo[i].flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
getSizeHAnim(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
|
|
|
if(hanim->hierarchy)
|
|
|
|
return 12 + 8 + hanim->hierarchy->numNodes*12;
|
|
|
|
return 12;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
registerHAnimPlugin(void)
|
2015-01-17 15:15:03 +01:00
|
|
|
{
|
2015-01-25 22:27:03 +01:00
|
|
|
hAnimOffset = Frame::registerPlugin(sizeof(HAnimData), ID_HANIMPLUGIN,
|
2015-01-17 15:15:03 +01:00
|
|
|
createHAnim,
|
|
|
|
destroyHAnim, copyHAnim);
|
|
|
|
Frame::registerPluginStream(ID_HANIMPLUGIN,
|
|
|
|
readHAnim,
|
|
|
|
writeHAnim,
|
|
|
|
getSizeHAnim);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-07 23:06:44 +01:00
|
|
|
//
|
|
|
|
// Geometry
|
|
|
|
//
|
|
|
|
|
|
|
|
// Mesh
|
|
|
|
|
|
|
|
static void
|
|
|
|
readMesh(Stream *stream, int32 len, void *object, int32, int32)
|
|
|
|
{
|
|
|
|
Geometry *geo = (Geometry*)object;
|
|
|
|
int32 indbuf[256];
|
|
|
|
uint32 buf[3];
|
|
|
|
stream->read(buf, 12);
|
|
|
|
geo->meshHeader = new MeshHeader;
|
|
|
|
geo->meshHeader->flags = buf[0];
|
|
|
|
geo->meshHeader->numMeshes = buf[1];
|
|
|
|
geo->meshHeader->totalIndices = buf[2];
|
|
|
|
geo->meshHeader->mesh = new Mesh[geo->meshHeader->numMeshes];
|
|
|
|
Mesh *mesh = geo->meshHeader->mesh;
|
|
|
|
bool hasData = len > 12+geo->meshHeader->numMeshes*8;
|
|
|
|
for(uint32 i = 0; i < geo->meshHeader->numMeshes; i++){
|
|
|
|
stream->read(buf, 8);
|
|
|
|
mesh->numIndices = buf[0];
|
|
|
|
mesh->material = geo->materialList[buf[1]];
|
|
|
|
mesh->indices = NULL;
|
|
|
|
if(geo->geoflags & Geometry::NATIVE){
|
|
|
|
// OpenGL stores uint16 indices here
|
|
|
|
if(hasData){
|
|
|
|
mesh->indices = new uint16[mesh->numIndices];
|
|
|
|
stream->read(mesh->indices,
|
|
|
|
mesh->numIndices*2);
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
mesh->indices = new uint16[mesh->numIndices];
|
|
|
|
uint16 *ind = mesh->indices;
|
|
|
|
int32 numIndices = mesh->numIndices;
|
|
|
|
for(; numIndices > 0; numIndices -= 256){
|
|
|
|
int32 n = numIndices < 256 ? numIndices : 256;
|
|
|
|
stream->read(indbuf, n*4);
|
|
|
|
for(int32 j = 0; j < n; j++)
|
|
|
|
ind[j] = indbuf[j];
|
|
|
|
ind += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mesh++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeMesh(Stream *stream, int32, void *object, int32, int32)
|
|
|
|
{
|
|
|
|
Geometry *geo = (Geometry*)object;
|
|
|
|
int32 indbuf[256];
|
|
|
|
uint32 buf[3];
|
|
|
|
buf[0] = geo->meshHeader->flags;
|
|
|
|
buf[1] = geo->meshHeader->numMeshes;
|
|
|
|
buf[2] = geo->meshHeader->totalIndices;
|
|
|
|
stream->write(buf, 12);
|
|
|
|
Mesh *mesh = geo->meshHeader->mesh;
|
|
|
|
for(uint32 i = 0; i < geo->meshHeader->numMeshes; i++){
|
|
|
|
buf[0] = mesh->numIndices;
|
|
|
|
buf[1] = findPointer((void*)mesh->material,
|
|
|
|
(void**)geo->materialList,
|
|
|
|
geo->numMaterials);
|
|
|
|
stream->write(buf, 8);
|
|
|
|
if(geo->geoflags & Geometry::NATIVE){
|
|
|
|
assert(geo->instData != NULL);
|
|
|
|
if(geo->instData->platform == PLATFORM_OGL)
|
|
|
|
stream->write(mesh->indices,
|
|
|
|
mesh->numIndices*2);
|
|
|
|
}else{
|
|
|
|
uint16 *ind = mesh->indices;
|
|
|
|
int32 numIndices = mesh->numIndices;
|
|
|
|
for(; numIndices > 0; numIndices -= 256){
|
|
|
|
int32 n = numIndices < 256 ? numIndices : 256;
|
|
|
|
for(int32 j = 0; j < n; j++)
|
|
|
|
indbuf[j] = ind[j];
|
|
|
|
stream->write(indbuf, n*4);
|
|
|
|
ind += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mesh++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
2015-01-26 10:15:26 +01:00
|
|
|
getSizeMesh(void *object, int32, int32)
|
2015-01-07 23:06:44 +01:00
|
|
|
{
|
|
|
|
Geometry *geo = (Geometry*)object;
|
|
|
|
if(geo->meshHeader == NULL)
|
|
|
|
return -1;
|
|
|
|
int32 size = 12 + geo->meshHeader->numMeshes*8;
|
|
|
|
if(geo->geoflags & Geometry::NATIVE){
|
|
|
|
assert(geo->instData != NULL);
|
|
|
|
if(geo->instData->platform == PLATFORM_OGL)
|
|
|
|
size += geo->meshHeader->totalIndices*2;
|
|
|
|
}else{
|
|
|
|
size += geo->meshHeader->totalIndices*4;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
registerMeshPlugin(void)
|
2015-01-07 23:06:44 +01:00
|
|
|
{
|
|
|
|
Geometry::registerPlugin(0, 0x50E, NULL, NULL, NULL);
|
2015-01-25 22:27:03 +01:00
|
|
|
Geometry::registerPluginStream(0x50E, readMesh, writeMesh, getSizeMesh);
|
2015-01-07 23:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Native Data
|
|
|
|
|
|
|
|
static void*
|
|
|
|
destroyNativeData(void *object, int32 offset, int32 size)
|
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
if(geometry->instData == NULL)
|
|
|
|
return object;
|
|
|
|
if(geometry->instData->platform == PLATFORM_PS2)
|
2015-01-25 22:27:03 +01:00
|
|
|
return ps2::destroyNativeData(object, offset, size);
|
2015-01-07 23:06:44 +01:00
|
|
|
if(geometry->instData->platform == PLATFORM_OGL)
|
2015-01-25 22:27:03 +01:00
|
|
|
return gl::destroyNativeData(object, offset, size);
|
2015-01-07 23:06:44 +01:00
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
readNativeData(Stream *stream, int32 len, void *object, int32 o, int32 s)
|
|
|
|
{
|
|
|
|
ChunkHeaderInfo header;
|
|
|
|
uint32 libid;
|
|
|
|
uint32 platform;
|
|
|
|
// ugly hack to find out platform
|
|
|
|
stream->seek(-4);
|
|
|
|
libid = stream->readU32();
|
2015-01-25 22:27:03 +01:00
|
|
|
readChunkHeaderInfo(stream, &header);
|
2015-01-07 23:06:44 +01:00
|
|
|
if(header.type == ID_STRUCT &&
|
2015-01-25 22:27:03 +01:00
|
|
|
libraryIDPack(header.version, header.build) == libid){
|
2015-01-07 23:06:44 +01:00
|
|
|
// must be PS2 or Xbox
|
|
|
|
platform = stream->readU32();
|
|
|
|
stream->seek(-16);
|
|
|
|
if(platform == PLATFORM_PS2)
|
2015-01-25 22:27:03 +01:00
|
|
|
ps2::readNativeData(stream, len, object, o, s);
|
2015-01-07 23:06:44 +01:00
|
|
|
else if(platform == PLATFORM_XBOX)
|
|
|
|
stream->seek(len);
|
|
|
|
}else{
|
|
|
|
stream->seek(-12);
|
2015-01-25 22:27:03 +01:00
|
|
|
gl::readNativeData(stream, len, object, o, s);
|
2015-01-07 23:06:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeNativeData(Stream *stream, int32 len, void *object, int32 o, int32 s)
|
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
if(geometry->instData == NULL)
|
|
|
|
return;
|
|
|
|
if(geometry->instData->platform == PLATFORM_PS2)
|
2015-01-25 22:27:03 +01:00
|
|
|
ps2::writeNativeData(stream, len, object, o, s);
|
2015-01-07 23:06:44 +01:00
|
|
|
else if(geometry->instData->platform == PLATFORM_OGL)
|
2015-01-25 22:27:03 +01:00
|
|
|
gl::writeNativeData(stream, len, object, o, s);
|
2015-01-07 23:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
getSizeNativeData(void *object, int32 offset, int32 size)
|
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
if(geometry->instData == NULL)
|
|
|
|
return -1;
|
|
|
|
if(geometry->instData->platform == PLATFORM_PS2)
|
2015-01-25 22:27:03 +01:00
|
|
|
return ps2::getSizeNativeData(object, offset, size);
|
2015-01-07 23:06:44 +01:00
|
|
|
else if(geometry->instData->platform == PLATFORM_XBOX)
|
|
|
|
return -1;
|
|
|
|
else if(geometry->instData->platform == PLATFORM_OGL)
|
2015-01-25 22:27:03 +01:00
|
|
|
return gl::getSizeNativeData(object, offset, size);
|
2015-01-07 23:06:44 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
registerNativeDataPlugin(void)
|
2015-01-07 23:06:44 +01:00
|
|
|
{
|
|
|
|
Geometry::registerPlugin(0, ID_NATIVEDATA,
|
|
|
|
NULL, destroyNativeData, NULL);
|
|
|
|
Geometry::registerPluginStream(ID_NATIVEDATA,
|
2015-01-25 22:27:03 +01:00
|
|
|
readNativeData,
|
|
|
|
writeNativeData,
|
|
|
|
getSizeNativeData);
|
2015-01-07 23:06:44 +01:00
|
|
|
}
|
|
|
|
|
2015-01-17 15:15:03 +01:00
|
|
|
//
|
2015-01-07 23:06:44 +01:00
|
|
|
// Skin
|
2015-01-17 15:15:03 +01:00
|
|
|
//
|
2015-01-07 23:06:44 +01:00
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
SkinGlobals skinGlobals = { 0, NULL };
|
2015-01-10 22:13:27 +01:00
|
|
|
|
2015-01-07 23:06:44 +01:00
|
|
|
static void*
|
|
|
|
createSkin(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
*PLUGINOFFSET(Skin*, object, offset) = NULL;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
destroySkin(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
|
|
|
if(skin)
|
|
|
|
delete[] skin->data;
|
|
|
|
delete skin;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
copySkin(void *dst, void *src, int32 offset, int32)
|
|
|
|
{
|
|
|
|
Skin *srcskin = *PLUGINOFFSET(Skin*, src, offset);
|
|
|
|
if(srcskin == NULL)
|
|
|
|
return dst;
|
2015-01-09 20:17:32 +01:00
|
|
|
Geometry *geometry = (Geometry*)src;
|
|
|
|
assert(geometry->instData == NULL);
|
|
|
|
assert(((Geometry*)src)->numVertices == ((Geometry*)dst)->numVertices);
|
2015-01-07 23:06:44 +01:00
|
|
|
Skin *dstskin = new Skin;
|
|
|
|
*PLUGINOFFSET(Skin*, dst, offset) = dstskin;
|
|
|
|
dstskin->numBones = srcskin->numBones;
|
|
|
|
dstskin->numUsedBones = srcskin->numUsedBones;
|
|
|
|
dstskin->maxIndex = srcskin->maxIndex;
|
|
|
|
|
2015-08-11 20:57:43 +02:00
|
|
|
dstskin->allocateData(geometry->numVertices);
|
|
|
|
memcpy(dstskin->usedBones, srcskin->usedBones, srcskin->numUsedBones);
|
|
|
|
memcpy(dstskin->inverseMatrices, srcskin->inverseMatrices,
|
|
|
|
srcskin->numBones*64);
|
|
|
|
memcpy(dstskin->indices, srcskin->indices, geometry->numVertices*4);
|
|
|
|
memcpy(dstskin->weights, srcskin->weights, geometry->numVertices*16);
|
2015-01-07 23:06:44 +01:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
readSkin(Stream *stream, int32 len, void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
uint8 header[4];
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
|
|
|
|
if(geometry->instData){
|
2015-01-10 16:55:13 +01:00
|
|
|
if(geometry->instData->platform == PLATFORM_PS2)
|
2015-01-25 22:27:03 +01:00
|
|
|
ps2::readNativeSkin(stream, len, object, offset);
|
2015-01-10 16:55:13 +01:00
|
|
|
else if(geometry->instData->platform == PLATFORM_OGL)
|
2015-01-25 22:27:03 +01:00
|
|
|
gl::readNativeSkin(stream, len, object, offset);
|
2015-01-10 16:55:13 +01:00
|
|
|
else
|
|
|
|
assert(0 && "unsupported native skin platform");
|
2015-01-07 23:06:44 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
2015-08-11 20:57:43 +02:00
|
|
|
// probably rw::version >= 0x34000
|
2015-01-07 23:06:44 +01:00
|
|
|
bool oldFormat = skin->numUsedBones == 0;
|
2015-08-11 20:57:43 +02:00
|
|
|
skin->allocateData(geometry->numVertices);
|
2015-01-07 23:06:44 +01:00
|
|
|
|
|
|
|
if(skin->usedBones)
|
|
|
|
stream->read(skin->usedBones, skin->numUsedBones);
|
|
|
|
if(skin->indices)
|
|
|
|
stream->read(skin->indices, geometry->numVertices*4);
|
|
|
|
if(skin->weights)
|
|
|
|
stream->read(skin->weights, geometry->numVertices*16);
|
|
|
|
for(int32 i = 0; i < skin->numBones; i++){
|
|
|
|
if(oldFormat)
|
|
|
|
stream->seek(4); // skip 0xdeaddead
|
|
|
|
stream->read(&skin->inverseMatrices[i*16], 64);
|
|
|
|
}
|
|
|
|
// TODO: find out what this is (related to skin splitting)
|
|
|
|
// always 0 in GTA files
|
|
|
|
if(!oldFormat)
|
|
|
|
stream->seek(12);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeSkin(Stream *stream, int32 len, void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
uint8 header[4];
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
|
|
|
|
if(geometry->instData){
|
2015-01-10 16:55:13 +01:00
|
|
|
if(geometry->instData->platform == PLATFORM_PS2)
|
2015-01-25 22:27:03 +01:00
|
|
|
ps2::writeNativeSkin(stream, len, object, offset);
|
2015-01-10 16:55:13 +01:00
|
|
|
else if(geometry->instData->platform == PLATFORM_OGL)
|
2015-01-25 22:27:03 +01:00
|
|
|
gl::writeNativeSkin(stream, len, object, offset);
|
2015-01-10 16:55:13 +01:00
|
|
|
else
|
|
|
|
assert(0 && "unsupported native skin platform");
|
2015-01-07 23:06:44 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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->indices, geometry->numVertices*4);
|
|
|
|
stream->write(skin->weights, geometry->numVertices*16);
|
|
|
|
for(int32 i = 0; i < skin->numBones; i++){
|
|
|
|
if(oldFormat)
|
|
|
|
stream->writeU32(0xdeaddead);
|
|
|
|
stream->write(&skin->inverseMatrices[i*16], 64);
|
|
|
|
}
|
|
|
|
if(!oldFormat){
|
|
|
|
uint32 buffer[3] = { 0, 0, 0};
|
|
|
|
stream->write(buffer, 12);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
getSizeSkin(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
Geometry *geometry = (Geometry*)object;
|
|
|
|
|
|
|
|
if(geometry->instData){
|
2015-01-10 16:55:13 +01:00
|
|
|
if(geometry->instData->platform == PLATFORM_PS2)
|
2015-01-25 22:27:03 +01:00
|
|
|
return ps2::getSizeNativeSkin(object, offset);
|
2015-01-10 16:55:13 +01:00
|
|
|
if(geometry->instData->platform == PLATFORM_OGL)
|
2015-01-25 22:27:03 +01:00
|
|
|
return gl::getSizeNativeSkin(object, offset);
|
2015-01-10 16:55:13 +01:00
|
|
|
assert(0 && "unsupported native skin platform");
|
2015-01-07 23:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
|
|
|
if(skin == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int32 size = 4 + geometry->numVertices*(16+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->numBones*4;
|
|
|
|
else
|
|
|
|
size += skin->numUsedBones + 12;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2015-01-10 22:13:27 +01:00
|
|
|
static void
|
2015-07-11 23:48:11 +02:00
|
|
|
skinRights(void *object, int32, int32, uint32)
|
2015-01-10 22:13:27 +01:00
|
|
|
{
|
2015-07-11 23:48:11 +02:00
|
|
|
((Atomic*)object)->pipeline = skinGlobals.pipelines[platformIdx[platform]];
|
2015-01-10 22:13:27 +01:00
|
|
|
}
|
|
|
|
|
2015-01-07 23:06:44 +01:00
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
registerSkinPlugin(void)
|
2015-01-07 23:06:44 +01:00
|
|
|
{
|
2015-08-02 19:31:01 +02:00
|
|
|
ObjPipeline *defpipe = new ObjPipeline(PLATFORM_NULL);
|
2015-07-11 23:48:11 +02:00
|
|
|
defpipe->pluginID = ID_SKIN;
|
|
|
|
defpipe->pluginData = 1;
|
|
|
|
for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++)
|
|
|
|
skinGlobals.pipelines[i] = defpipe;
|
2015-07-12 22:57:05 +02:00
|
|
|
skinGlobals.pipelines[platformIdx[PLATFORM_PS2]] =
|
|
|
|
ps2::makeSkinPipeline();
|
2015-08-03 18:30:10 +02:00
|
|
|
skinGlobals.pipelines[platformIdx[PLATFORM_OGL]] =
|
|
|
|
gl::makeSkinPipeline();
|
2015-01-10 22:13:27 +01:00
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
skinGlobals.offset = Geometry::registerPlugin(sizeof(Skin*), ID_SKIN,
|
|
|
|
createSkin,
|
|
|
|
destroySkin,
|
|
|
|
copySkin);
|
2015-01-07 23:06:44 +01:00
|
|
|
Geometry::registerPluginStream(ID_SKIN,
|
2015-01-09 20:17:32 +01:00
|
|
|
readSkin, writeSkin, getSizeSkin);
|
2015-01-25 22:27:03 +01:00
|
|
|
Atomic::registerPlugin(0, ID_SKIN, NULL, NULL, NULL);
|
2015-01-10 22:13:27 +01:00
|
|
|
Atomic::setStreamRightsCallback(ID_SKIN, skinRights);
|
2015-01-09 20:17:32 +01:00
|
|
|
}
|
|
|
|
|
2015-08-11 20:57:43 +02:00
|
|
|
void
|
|
|
|
Skin::allocateData(int32 numVerts)
|
|
|
|
{
|
|
|
|
uint32 size = this->numUsedBones +
|
|
|
|
this->numBones*64 +
|
|
|
|
numVerts*(16+4) + 15;
|
|
|
|
this->data = new uint8[size];
|
|
|
|
uint8 *data = this->data;
|
|
|
|
|
|
|
|
this->usedBones = NULL;
|
|
|
|
if(this->numUsedBones){
|
|
|
|
this->usedBones = data;
|
|
|
|
data += this->numUsedBones;
|
|
|
|
}
|
|
|
|
|
|
|
|
uintptr ptr = (uintptr)data + 15;
|
|
|
|
ptr &= ~0xF;
|
|
|
|
data = (uint8*)ptr;
|
|
|
|
this->inverseMatrices = NULL;
|
|
|
|
if(this->numBones){
|
|
|
|
this->inverseMatrices = (float*)data;
|
|
|
|
data += 64*this->numBones;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->indices = NULL;
|
|
|
|
if(numVerts){
|
|
|
|
this->indices = data;
|
|
|
|
data += 4*numVerts;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->weights = NULL;
|
|
|
|
if(numVerts)
|
|
|
|
this->weights = (float*)data;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Skin::allocateVertexData(int32 numVerts)
|
|
|
|
{
|
|
|
|
uint8 *usedBones = this->usedBones;
|
|
|
|
float *invMats = this->inverseMatrices;
|
|
|
|
uint8 *data = this->data;
|
|
|
|
|
|
|
|
this->allocateData(numVerts);
|
|
|
|
memcpy(this->usedBones, usedBones, this->numUsedBones);
|
|
|
|
memcpy(this->inverseMatrices, invMats, this->numBones*64);
|
|
|
|
delete[] data;
|
|
|
|
}
|
|
|
|
|
2015-01-17 15:15:03 +01:00
|
|
|
//
|
|
|
|
// MatFX
|
|
|
|
//
|
|
|
|
|
|
|
|
// Atomic
|
2015-01-09 20:17:32 +01:00
|
|
|
|
|
|
|
static void*
|
|
|
|
createAtomicMatFX(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
*PLUGINOFFSET(int32, object, offset) = 0;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
copyAtomicMatFX(void *dst, void *src, int32 offset, int32)
|
|
|
|
{
|
|
|
|
*PLUGINOFFSET(int32, dst, offset) = *PLUGINOFFSET(int32, src, offset);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
readAtomicMatFX(Stream *stream, int32, void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
int32 flag;
|
|
|
|
stream->read(&flag, 4);
|
2015-08-01 23:03:10 +02:00
|
|
|
// printf("matfx: %d\n", flag);
|
2015-01-09 20:17:32 +01:00
|
|
|
*PLUGINOFFSET(int32, object, offset) = flag;
|
2015-01-10 22:13:27 +01:00
|
|
|
if(flag)
|
2015-07-11 23:48:11 +02:00
|
|
|
((Atomic*)object)->pipeline =
|
|
|
|
matFXGlobals.pipelines[platformIdx[rw::platform]];
|
2015-01-09 20:17:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeAtomicMatFX(Stream *stream, int32, void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
int32 flag;
|
|
|
|
flag = *PLUGINOFFSET(int32, object, offset);
|
|
|
|
stream->writeI32(flag);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
getSizeAtomicMatFX(void *object, int32 offset, int32)
|
|
|
|
{
|
2015-08-11 20:57:43 +02:00
|
|
|
// TODO: version dependent
|
2015-08-01 23:03:10 +02:00
|
|
|
/* int32 flag;
|
2015-01-09 20:17:32 +01:00
|
|
|
flag = *PLUGINOFFSET(int32, object, offset);
|
2015-08-01 23:03:10 +02:00
|
|
|
return flag ? 4 : -1; */
|
|
|
|
return 4;
|
2015-01-09 20:17:32 +01:00
|
|
|
}
|
|
|
|
|
2015-01-17 15:15:03 +01:00
|
|
|
// Material
|
2015-01-09 20:17:32 +01:00
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
MatFXGlobals matFXGlobals = { 0, 0, NULL };
|
2015-01-10 22:13:27 +01:00
|
|
|
|
2015-01-09 20:17:32 +01:00
|
|
|
// TODO: Frames and Matrices?
|
|
|
|
static void
|
|
|
|
clearMatFX(MatFX *matfx)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
switch(matfx->fx[i].type){
|
|
|
|
case MatFX::BUMPMAP:
|
|
|
|
if(matfx->fx[i].bump.bumpedTex)
|
|
|
|
matfx->fx[i].bump.bumpedTex->decRef();
|
|
|
|
if(matfx->fx[i].bump.tex)
|
|
|
|
matfx->fx[i].bump.tex->decRef();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::ENVMAP:
|
|
|
|
if(matfx->fx[i].env.tex)
|
|
|
|
matfx->fx[i].env.tex->decRef();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::DUAL:
|
|
|
|
if(matfx->fx[i].dual.tex)
|
|
|
|
matfx->fx[i].dual.tex->decRef();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
memset(matfx, 0, sizeof(MatFX));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MatFX::setEffects(uint32 flags)
|
|
|
|
{
|
|
|
|
if(this->flags != 0 && this->flags != flags)
|
|
|
|
clearMatFX(this);
|
|
|
|
this->flags = flags;
|
|
|
|
switch(flags){
|
|
|
|
case BUMPMAP:
|
|
|
|
case ENVMAP:
|
|
|
|
case DUAL:
|
|
|
|
case UVTRANSFORM:
|
|
|
|
this->fx[0].type = flags;
|
|
|
|
this->fx[1].type = NOTHING;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BUMPENVMAP:
|
|
|
|
this->fx[0].type = BUMPMAP;
|
|
|
|
this->fx[1].type = ENVMAP;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DUALUVTRANSFORM:
|
|
|
|
this->fx[0].type = UVTRANSFORM;
|
|
|
|
this->fx[1].type = DUAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32
|
|
|
|
MatFX::getEffectIndex(uint32 type)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
if(this->fx[i].type == type)
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
createMaterialMatFX(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
*PLUGINOFFSET(MatFX*, object, offset) = NULL;
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
destroyMaterialMatFX(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset);
|
|
|
|
if(matfx){
|
|
|
|
clearMatFX(matfx);
|
|
|
|
delete matfx;
|
|
|
|
}
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void*
|
|
|
|
copyMaterialMatFX(void *dst, void *src, int32 offset, int32)
|
|
|
|
{
|
|
|
|
MatFX *srcfx = *PLUGINOFFSET(MatFX*, src, offset);
|
|
|
|
if(srcfx == NULL)
|
|
|
|
return dst;
|
|
|
|
MatFX *dstfx = new MatFX;
|
|
|
|
*PLUGINOFFSET(MatFX*, dst, offset) = dstfx;
|
|
|
|
memcpy(dstfx, srcfx, sizeof(MatFX));
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
switch(dstfx->fx[i].type){
|
|
|
|
case MatFX::BUMPMAP:
|
|
|
|
if(dstfx->fx[i].bump.bumpedTex)
|
|
|
|
dstfx->fx[i].bump.bumpedTex->refCount++;
|
|
|
|
if(dstfx->fx[i].bump.tex)
|
|
|
|
dstfx->fx[i].bump.tex->refCount++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::ENVMAP:
|
|
|
|
if(dstfx->fx[i].env.tex)
|
|
|
|
dstfx->fx[i].env.tex->refCount++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::DUAL:
|
|
|
|
if(dstfx->fx[i].dual.tex)
|
|
|
|
dstfx->fx[i].dual.tex->refCount++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
readMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
Texture *tex, *bumpedTex;
|
|
|
|
float coefficient;
|
|
|
|
int32 fbAlpha;
|
|
|
|
int32 srcBlend, dstBlend;
|
|
|
|
int32 idx;
|
|
|
|
|
|
|
|
MatFX *matfx = new MatFX;
|
|
|
|
memset(matfx, 0, sizeof(MatFX));
|
|
|
|
*PLUGINOFFSET(MatFX*, object, offset) = matfx;
|
|
|
|
matfx->setEffects(stream->readU32());
|
|
|
|
|
|
|
|
for(int i = 0; i < 2; i++){
|
|
|
|
uint32 type = stream->readU32();
|
|
|
|
switch(type){
|
|
|
|
case MatFX::BUMPMAP:
|
|
|
|
coefficient = stream->readF32();
|
|
|
|
bumpedTex = tex = NULL;
|
|
|
|
if(stream->readI32()){
|
2015-01-25 22:27:03 +01:00
|
|
|
assert(findChunk(stream, ID_TEXTURE,
|
2015-01-09 20:17:32 +01:00
|
|
|
NULL, NULL));
|
|
|
|
bumpedTex = Texture::streamRead(stream);
|
|
|
|
}
|
|
|
|
if(stream->readI32()){
|
2015-01-25 22:27:03 +01:00
|
|
|
assert(findChunk(stream, ID_TEXTURE,
|
2015-01-09 20:17:32 +01:00
|
|
|
NULL, NULL));
|
|
|
|
tex = Texture::streamRead(stream);
|
|
|
|
}
|
|
|
|
idx = matfx->getEffectIndex(type);
|
|
|
|
assert(idx >= 0);
|
|
|
|
matfx->fx[idx].bump.bumpedTex = bumpedTex;
|
|
|
|
matfx->fx[idx].bump.tex = tex;
|
|
|
|
matfx->fx[idx].bump.coefficient = coefficient;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::ENVMAP:
|
|
|
|
coefficient = stream->readF32();
|
|
|
|
fbAlpha = stream->readI32();
|
|
|
|
tex = NULL;
|
|
|
|
if(stream->readI32()){
|
2015-01-25 22:27:03 +01:00
|
|
|
assert(findChunk(stream, ID_TEXTURE,
|
2015-01-09 20:17:32 +01:00
|
|
|
NULL, NULL));
|
|
|
|
tex = Texture::streamRead(stream);
|
|
|
|
}
|
|
|
|
idx = matfx->getEffectIndex(type);
|
|
|
|
assert(idx >= 0);
|
|
|
|
matfx->fx[idx].env.tex = tex;
|
|
|
|
matfx->fx[idx].env.fbAlpha = fbAlpha;
|
|
|
|
matfx->fx[idx].env.coefficient = coefficient;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::DUAL:
|
|
|
|
srcBlend = stream->readI32();
|
|
|
|
dstBlend = stream->readI32();
|
|
|
|
tex = NULL;
|
|
|
|
if(stream->readI32()){
|
2015-01-25 22:27:03 +01:00
|
|
|
assert(findChunk(stream, ID_TEXTURE,
|
2015-01-09 20:17:32 +01:00
|
|
|
NULL, NULL));
|
|
|
|
tex = Texture::streamRead(stream);
|
|
|
|
}
|
|
|
|
idx = matfx->getEffectIndex(type);
|
|
|
|
assert(idx >= 0);
|
|
|
|
matfx->fx[idx].dual.tex = tex;
|
|
|
|
matfx->fx[idx].dual.srcBlend = srcBlend;
|
|
|
|
matfx->fx[idx].dual.dstBlend = dstBlend;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writeMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset);
|
|
|
|
|
|
|
|
stream->writeU32(matfx->flags);
|
|
|
|
for(int i = 0; i < 2; i++){
|
|
|
|
stream->writeU32(matfx->fx[i].type);
|
|
|
|
switch(matfx->fx[i].type){
|
|
|
|
case MatFX::BUMPMAP:
|
|
|
|
stream->writeF32(matfx->fx[i].bump.coefficient);
|
|
|
|
stream->writeI32(matfx->fx[i].bump.bumpedTex != NULL);
|
|
|
|
if(matfx->fx[i].bump.bumpedTex)
|
|
|
|
matfx->fx[i].bump.bumpedTex->streamWrite(stream);
|
|
|
|
stream->writeI32(matfx->fx[i].bump.tex != NULL);
|
|
|
|
if(matfx->fx[i].bump.tex)
|
|
|
|
matfx->fx[i].bump.tex->streamWrite(stream);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::ENVMAP:
|
|
|
|
stream->writeF32(matfx->fx[i].env.coefficient);
|
|
|
|
stream->writeI32(matfx->fx[i].env.fbAlpha);
|
|
|
|
stream->writeI32(matfx->fx[i].env.tex != NULL);
|
|
|
|
if(matfx->fx[i].env.tex)
|
|
|
|
matfx->fx[i].env.tex->streamWrite(stream);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::DUAL:
|
|
|
|
stream->writeI32(matfx->fx[i].dual.srcBlend);
|
|
|
|
stream->writeI32(matfx->fx[i].dual.dstBlend);
|
|
|
|
stream->writeI32(matfx->fx[i].dual.tex != NULL);
|
|
|
|
if(matfx->fx[i].dual.tex)
|
|
|
|
matfx->fx[i].dual.tex->streamWrite(stream);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
getSizeMaterialMatFX(void *object, int32 offset, int32)
|
|
|
|
{
|
|
|
|
MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset);
|
|
|
|
if(matfx == NULL)
|
|
|
|
return -1;
|
|
|
|
int32 size = 4 + 4 + 4;
|
|
|
|
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
|
|
switch(matfx->fx[i].type){
|
|
|
|
case MatFX::BUMPMAP:
|
|
|
|
size += 4 + 4 + 4;
|
|
|
|
if(matfx->fx[i].bump.bumpedTex)
|
|
|
|
size += 12 +
|
|
|
|
matfx->fx[i].bump.bumpedTex->streamGetSize();
|
|
|
|
if(matfx->fx[i].bump.tex)
|
|
|
|
size += 12 +
|
|
|
|
matfx->fx[i].bump.tex->streamGetSize();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::ENVMAP:
|
|
|
|
size += 4 + 4 + 4;
|
|
|
|
if(matfx->fx[i].env.tex)
|
|
|
|
size += 12 +
|
|
|
|
matfx->fx[i].env.tex->streamGetSize();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MatFX::DUAL:
|
|
|
|
size += 4 + 4 + 4;
|
|
|
|
if(matfx->fx[i].dual.tex)
|
|
|
|
size += 12 +
|
|
|
|
matfx->fx[i].dual.tex->streamGetSize();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-01-25 22:27:03 +01:00
|
|
|
registerMatFXPlugin(void)
|
2015-01-09 20:17:32 +01:00
|
|
|
{
|
2015-08-02 19:31:01 +02:00
|
|
|
ObjPipeline *defpipe = new ObjPipeline(PLATFORM_NULL);
|
2015-07-11 23:48:11 +02:00
|
|
|
defpipe->pluginID = ID_MATFX;
|
|
|
|
defpipe->pluginData = 0;
|
|
|
|
for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++)
|
|
|
|
matFXGlobals.pipelines[i] = defpipe;
|
2015-07-12 22:57:05 +02:00
|
|
|
matFXGlobals.pipelines[platformIdx[PLATFORM_PS2]] =
|
|
|
|
ps2::makeMatFXPipeline();
|
2015-08-03 18:30:10 +02:00
|
|
|
matFXGlobals.pipelines[platformIdx[PLATFORM_OGL]] =
|
|
|
|
gl::makeMatFXPipeline();
|
2015-01-10 22:13:27 +01:00
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
matFXGlobals.atomicOffset =
|
2015-01-09 20:17:32 +01:00
|
|
|
Atomic::registerPlugin(sizeof(int32), ID_MATFX,
|
|
|
|
createAtomicMatFX, NULL, copyAtomicMatFX);
|
|
|
|
Atomic::registerPluginStream(ID_MATFX,
|
|
|
|
readAtomicMatFX,
|
|
|
|
writeAtomicMatFX,
|
|
|
|
getSizeAtomicMatFX);
|
2015-01-10 22:13:27 +01:00
|
|
|
|
2015-01-25 22:27:03 +01:00
|
|
|
matFXGlobals.materialOffset =
|
2015-01-09 20:17:32 +01:00
|
|
|
Material::registerPlugin(sizeof(MatFX*), ID_MATFX,
|
|
|
|
createMaterialMatFX, destroyMaterialMatFX,
|
|
|
|
copyMaterialMatFX);
|
|
|
|
Material::registerPluginStream(ID_MATFX,
|
|
|
|
readMaterialMatFX,
|
|
|
|
writeMaterialMatFX,
|
|
|
|
getSizeMaterialMatFX);
|
2015-01-07 23:06:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|