mirror of
https://github.com/aap/librw.git
synced 2024-11-25 21:25:42 +00:00
split up some files
This commit is contained in:
parent
dd901ebfa3
commit
53647520bc
3
Makefile
3
Makefile
@ -6,8 +6,7 @@ BUILDDEF:=$(shell echo $(BUILD) | tr a-z A-Z | sed 's/^/-DRW_/')
|
|||||||
BUILDDIR=build-$(BUILD)
|
BUILDDIR=build-$(BUILD)
|
||||||
SRCDIR=src
|
SRCDIR=src
|
||||||
#SRC := $(patsubst %.cpp,$(SRCDIR)/%.cpp, $(wildcard *.cpp))
|
#SRC := $(patsubst %.cpp,$(SRCDIR)/%.cpp, $(wildcard *.cpp))
|
||||||
SRC := $(wildcard $(SRCDIR)/*.cpp $(SRCDIR)/d3d/*.cpp $(SRCDIR)/ps2/*.cpp \
|
SRC := $(wildcard $(SRCDIR)/*.cpp $(SRCDIR)/*/*.cpp)
|
||||||
$(SRCDIR)/gl/*.cpp)
|
|
||||||
OBJ := $(patsubst $(SRCDIR)/%.cpp,$(BUILDDIR)/%.o,$(SRC))
|
OBJ := $(patsubst $(SRCDIR)/%.cpp,$(BUILDDIR)/%.o,$(SRC))
|
||||||
DEP := $(patsubst $(SRCDIR)/%.cpp,$(BUILDDIR)/%.d,$(SRC))
|
DEP := $(patsubst $(SRCDIR)/%.cpp,$(BUILDDIR)/%.d,$(SRC))
|
||||||
INC := -I/usr/local/include
|
INC := -I/usr/local/include
|
||||||
|
258
src/geoplg.cpp
Normal file
258
src/geoplg.cpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "rwbase.h"
|
||||||
|
#include "rwerror.h"
|
||||||
|
#include "rwplg.h"
|
||||||
|
#include "rwpipeline.h"
|
||||||
|
#include "rwobjects.h"
|
||||||
|
#include "rwplugins.h"
|
||||||
|
#include "ps2/rwps2.h"
|
||||||
|
#include "ps2/rwps2plg.h"
|
||||||
|
#include "d3d/rwxbox.h"
|
||||||
|
#include "d3d/rwd3d8.h"
|
||||||
|
#include "d3d/rwd3d9.h"
|
||||||
|
#include "gl/rwwdgl.h"
|
||||||
|
#include "gl/rwgl3.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID 2
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
|
||||||
|
// Mesh
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
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;
|
||||||
|
uint16 *p = nil;
|
||||||
|
if(!(geo->geoflags & Geometry::NATIVE) || hasData)
|
||||||
|
p = new uint16[geo->meshHeader->totalIndices];
|
||||||
|
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 = nil;
|
||||||
|
if(geo->geoflags & Geometry::NATIVE){
|
||||||
|
// OpenGL stores uint16 indices here
|
||||||
|
if(hasData){
|
||||||
|
mesh->indices = p;
|
||||||
|
p += mesh->numIndices;
|
||||||
|
stream->read(mesh->indices,
|
||||||
|
mesh->numIndices*2);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
mesh->indices = p;
|
||||||
|
p += 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++;
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
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 != nil);
|
||||||
|
if(geo->instData->platform == PLATFORM_WDGL)
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
getSizeMesh(void *object, int32, int32)
|
||||||
|
{
|
||||||
|
Geometry *geo = (Geometry*)object;
|
||||||
|
if(geo->meshHeader == nil)
|
||||||
|
return -1;
|
||||||
|
int32 size = 12 + geo->meshHeader->numMeshes*8;
|
||||||
|
if(geo->geoflags & Geometry::NATIVE){
|
||||||
|
assert(geo->instData != nil);
|
||||||
|
if(geo->instData->platform == PLATFORM_WDGL)
|
||||||
|
size += geo->meshHeader->totalIndices*2;
|
||||||
|
}else{
|
||||||
|
size += geo->meshHeader->totalIndices*4;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerMeshPlugin(void)
|
||||||
|
{
|
||||||
|
Geometry::registerPlugin(0, 0x50E, nil, nil, nil);
|
||||||
|
Geometry::registerPluginStream(0x50E, readMesh, writeMesh, getSizeMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshHeader::~MeshHeader(void)
|
||||||
|
{
|
||||||
|
// first mesh holds pointer to all indices
|
||||||
|
delete[] this->mesh[0].indices;
|
||||||
|
delete[] this->mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MeshHeader::allocateIndices(void)
|
||||||
|
{
|
||||||
|
uint16 *p = new uint16[this->totalIndices];
|
||||||
|
Mesh *mesh = this->mesh;
|
||||||
|
for(uint32 i = 0; i < this->numMeshes; i++){
|
||||||
|
mesh->indices = p;
|
||||||
|
p += mesh->numIndices;
|
||||||
|
mesh++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native Data
|
||||||
|
|
||||||
|
static void*
|
||||||
|
destroyNativeData(void *object, int32 offset, int32 size)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil)
|
||||||
|
return object;
|
||||||
|
if(geometry->instData->platform == PLATFORM_PS2)
|
||||||
|
return ps2::destroyNativeData(object, offset, size);
|
||||||
|
if(geometry->instData->platform == PLATFORM_WDGL)
|
||||||
|
return wdgl::destroyNativeData(object, offset, size);
|
||||||
|
if(geometry->instData->platform == PLATFORM_XBOX)
|
||||||
|
return xbox::destroyNativeData(object, offset, size);
|
||||||
|
if(geometry->instData->platform == PLATFORM_D3D8)
|
||||||
|
return d3d8::destroyNativeData(object, offset, size);
|
||||||
|
if(geometry->instData->platform == PLATFORM_D3D9)
|
||||||
|
return d3d9::destroyNativeData(object, offset, size);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
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();
|
||||||
|
readChunkHeaderInfo(stream, &header);
|
||||||
|
if(header.type == ID_STRUCT &&
|
||||||
|
libraryIDPack(header.version, header.build) == libid){
|
||||||
|
platform = stream->readU32();
|
||||||
|
stream->seek(-16);
|
||||||
|
if(platform == PLATFORM_PS2)
|
||||||
|
return ps2::readNativeData(stream, len, object, o, s);
|
||||||
|
else if(platform == PLATFORM_XBOX)
|
||||||
|
return xbox::readNativeData(stream, len, object, o, s);
|
||||||
|
else if(platform == PLATFORM_D3D8)
|
||||||
|
return d3d8::readNativeData(stream, len, object, o, s);
|
||||||
|
else if(platform == PLATFORM_D3D9)
|
||||||
|
return d3d9::readNativeData(stream, len, object, o, s);
|
||||||
|
else{
|
||||||
|
fprintf(stderr, "unknown platform %d\n", platform);
|
||||||
|
stream->seek(len);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
stream->seek(-12);
|
||||||
|
wdgl::readNativeData(stream, len, object, o, s);
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
writeNativeData(Stream *stream, int32 len, void *object, int32 o, int32 s)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil)
|
||||||
|
return stream;
|
||||||
|
if(geometry->instData->platform == PLATFORM_PS2)
|
||||||
|
return ps2::writeNativeData(stream, len, object, o, s);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_WDGL)
|
||||||
|
return wdgl::writeNativeData(stream, len, object, o, s);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_XBOX)
|
||||||
|
return xbox::writeNativeData(stream, len, object, o, s);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_D3D8)
|
||||||
|
return d3d8::writeNativeData(stream, len, object, o, s);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_D3D9)
|
||||||
|
return d3d9::writeNativeData(stream, len, object, o, s);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
getSizeNativeData(void *object, int32 offset, int32 size)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
if(geometry->instData == nil)
|
||||||
|
return 0;
|
||||||
|
if(geometry->instData->platform == PLATFORM_PS2)
|
||||||
|
return ps2::getSizeNativeData(object, offset, size);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_WDGL)
|
||||||
|
return wdgl::getSizeNativeData(object, offset, size);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_XBOX)
|
||||||
|
return xbox::getSizeNativeData(object, offset, size);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_D3D8)
|
||||||
|
return d3d8::getSizeNativeData(object, offset, size);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_D3D9)
|
||||||
|
return d3d9::getSizeNativeData(object, offset, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerNativeDataPlugin(void)
|
||||||
|
{
|
||||||
|
Geometry::registerPlugin(0, ID_NATIVEDATA,
|
||||||
|
nil, destroyNativeData, nil);
|
||||||
|
Geometry::registerPluginStream(ID_NATIVEDATA,
|
||||||
|
readNativeData,
|
||||||
|
writeNativeData,
|
||||||
|
getSizeNativeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
266
src/hanim.cpp
Normal file
266
src/hanim.cpp
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "rwbase.h"
|
||||||
|
#include "rwerror.h"
|
||||||
|
#include "rwplg.h"
|
||||||
|
#include "rwpipeline.h"
|
||||||
|
#include "rwobjects.h"
|
||||||
|
#include "rwplugins.h"
|
||||||
|
#include "ps2/rwps2.h"
|
||||||
|
#include "ps2/rwps2plg.h"
|
||||||
|
#include "d3d/rwxbox.h"
|
||||||
|
#include "d3d/rwd3d8.h"
|
||||||
|
#include "d3d/rwd3d9.h"
|
||||||
|
#include "gl/rwwdgl.h"
|
||||||
|
#include "gl/rwgl3.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID ID_HANIM
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
|
||||||
|
int32 hAnimOffset;
|
||||||
|
bool32 hAnimDoStream = 1;
|
||||||
|
|
||||||
|
HAnimHierarchy*
|
||||||
|
HAnimHierarchy::create(int32 numNodes, int32 *nodeFlags, int32 *nodeIDs, int32 flags, int32 maxKeySize)
|
||||||
|
{
|
||||||
|
HAnimHierarchy *hier = (HAnimHierarchy*)malloc(sizeof(*hier));
|
||||||
|
|
||||||
|
hier->numNodes = numNodes;
|
||||||
|
hier->flags = flags;
|
||||||
|
hier->maxInterpKeyFrameSize = maxKeySize;
|
||||||
|
hier->parentFrame = nil;
|
||||||
|
hier->parentHierarchy = hier;
|
||||||
|
if(hier->flags & 2)
|
||||||
|
hier->matrices = hier->matricesUnaligned = nil;
|
||||||
|
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 = nodeIDs[i];
|
||||||
|
hier->nodeInfo[i].index = i;
|
||||||
|
hier->nodeInfo[i].flags = nodeFlags[i];
|
||||||
|
hier->nodeInfo[i].frame = nil;
|
||||||
|
}
|
||||||
|
return hier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HAnimHierarchy::destroy(void)
|
||||||
|
{
|
||||||
|
delete[] (uint8*)this->matricesUnaligned;
|
||||||
|
delete[] this->nodeInfo;
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Frame*
|
||||||
|
findById(Frame *f, int32 id)
|
||||||
|
{
|
||||||
|
if(f == nil) return nil;
|
||||||
|
HAnimData *hanim = HAnimData::get(f);
|
||||||
|
if(hanim->id >= 0 && hanim->id == id) return f;
|
||||||
|
Frame *ff = findById(f->next, id);
|
||||||
|
if(ff) return ff;
|
||||||
|
return findById(f->child, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HAnimHierarchy::attachByIndex(int32 idx)
|
||||||
|
{
|
||||||
|
int32 id = this->nodeInfo[idx].id;
|
||||||
|
Frame *f = findById(this->parentFrame, id);
|
||||||
|
this->nodeInfo[idx].frame = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HAnimHierarchy::attach(void)
|
||||||
|
{
|
||||||
|
for(int32 i = 0; i < this->numNodes; i++)
|
||||||
|
this->attachByIndex(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32
|
||||||
|
HAnimHierarchy::getIndex(int32 id)
|
||||||
|
{
|
||||||
|
for(int32 i = 0; i < this->numNodes; i++)
|
||||||
|
if(this->nodeInfo[i].id == id)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAnimHierarchy*
|
||||||
|
HAnimHierarchy::get(Frame *f)
|
||||||
|
{
|
||||||
|
return HAnimData::get(f)->hierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAnimHierarchy*
|
||||||
|
HAnimHierarchy::find(Frame *f)
|
||||||
|
{
|
||||||
|
if(f == nil) return nil;
|
||||||
|
HAnimHierarchy *hier = HAnimHierarchy::get(f);
|
||||||
|
if(hier) return hier;
|
||||||
|
hier = HAnimHierarchy::find(f->next);
|
||||||
|
if(hier) return hier;
|
||||||
|
return HAnimHierarchy::find(f->child);
|
||||||
|
}
|
||||||
|
|
||||||
|
HAnimData*
|
||||||
|
HAnimData::get(Frame *f)
|
||||||
|
{
|
||||||
|
return PLUGINOFFSET(HAnimData, f, hAnimOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
createHAnim(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
||||||
|
hanim->id = -1;
|
||||||
|
hanim->hierarchy = nil;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
destroyHAnim(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
||||||
|
if(hanim->hierarchy)
|
||||||
|
hanim->hierarchy->destroy();
|
||||||
|
hanim->id = -1;
|
||||||
|
hanim->hierarchy = nil;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
copyHAnim(void *dst, void *src, int32 offset, int32)
|
||||||
|
{
|
||||||
|
HAnimData *dsthanim = PLUGINOFFSET(HAnimData, dst, offset);
|
||||||
|
HAnimData *srchanim = PLUGINOFFSET(HAnimData, src, offset);
|
||||||
|
dsthanim->id = srchanim->id;
|
||||||
|
// TODO
|
||||||
|
dsthanim->hierarchy = nil;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
readHAnim(Stream *stream, int32, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
int32 ver, numNodes;
|
||||||
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
||||||
|
ver = stream->readI32();
|
||||||
|
assert(ver == 0x100);
|
||||||
|
hanim->id = stream->readI32();
|
||||||
|
numNodes = stream->readI32();
|
||||||
|
if(numNodes != 0){
|
||||||
|
int32 flags = stream->readI32();
|
||||||
|
int32 maxKeySize = stream->readI32();
|
||||||
|
int32 *nodeFlags = new int32[numNodes];
|
||||||
|
int32 *nodeIDs = new int32[numNodes];
|
||||||
|
for(int32 i = 0; i < numNodes; i++){
|
||||||
|
nodeIDs[i] = stream->readI32();
|
||||||
|
stream->readI32(); // index...unused
|
||||||
|
nodeFlags[i] = stream->readI32();
|
||||||
|
}
|
||||||
|
hanim->hierarchy = HAnimHierarchy::create(numNodes,
|
||||||
|
nodeFlags, nodeIDs, flags, maxKeySize);
|
||||||
|
hanim->hierarchy->parentFrame = (Frame*)object;
|
||||||
|
delete[] nodeFlags;
|
||||||
|
delete[] nodeIDs;
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
writeHAnim(Stream *stream, int32, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
||||||
|
stream->writeI32(256);
|
||||||
|
stream->writeI32(hanim->id);
|
||||||
|
if(hanim->hierarchy == nil){
|
||||||
|
stream->writeI32(0);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
getSizeHAnim(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
HAnimData *hanim = PLUGINOFFSET(HAnimData, object, offset);
|
||||||
|
if(!hAnimDoStream ||
|
||||||
|
version >= 0x35000 && hanim->id == -1 && hanim->hierarchy == nil)
|
||||||
|
return 0;
|
||||||
|
if(hanim->hierarchy)
|
||||||
|
return 12 + 8 + hanim->hierarchy->numNodes*12;
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hAnimFrameRead(Stream *stream, Animation *anim)
|
||||||
|
{
|
||||||
|
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
||||||
|
for(int32 i = 0; i < anim->numFrames; i++){
|
||||||
|
frames[i].time = stream->readF32();
|
||||||
|
stream->read(frames[i].q, 4*4);
|
||||||
|
stream->read(frames[i].t, 3*4);
|
||||||
|
int32 prev = stream->readI32();
|
||||||
|
frames[i].prev = &frames[prev];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hAnimFrameWrite(Stream *stream, Animation *anim)
|
||||||
|
{
|
||||||
|
HAnimKeyFrame *frames = (HAnimKeyFrame*)anim->keyframes;
|
||||||
|
for(int32 i = 0; i < anim->numFrames; i++){
|
||||||
|
stream->writeF32(frames[i].time);
|
||||||
|
stream->write(frames[i].q, 4*4);
|
||||||
|
stream->write(frames[i].t, 3*4);
|
||||||
|
stream->writeI32(frames[i].prev - frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32
|
||||||
|
hAnimFrameGetSize(Animation *anim)
|
||||||
|
{
|
||||||
|
return anim->numFrames*(4 + 4*4 + 3*4 + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerHAnimPlugin(void)
|
||||||
|
{
|
||||||
|
hAnimOffset = Frame::registerPlugin(sizeof(HAnimData), ID_HANIMPLUGIN,
|
||||||
|
createHAnim,
|
||||||
|
destroyHAnim, copyHAnim);
|
||||||
|
Frame::registerPluginStream(ID_HANIMPLUGIN,
|
||||||
|
readHAnim,
|
||||||
|
writeHAnim,
|
||||||
|
getSizeHAnim);
|
||||||
|
|
||||||
|
AnimInterpolatorInfo *info = new AnimInterpolatorInfo;
|
||||||
|
info->id = 1;
|
||||||
|
info->keyFrameSize = sizeof(HAnimKeyFrame);
|
||||||
|
info->customDataSize = sizeof(HAnimKeyFrame);
|
||||||
|
info->streamRead = hAnimFrameRead;
|
||||||
|
info->streamWrite = hAnimFrameWrite;
|
||||||
|
info->streamGetSize = hAnimFrameGetSize;
|
||||||
|
registerAnimInterpolatorInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
451
src/matfx.cpp
Normal file
451
src/matfx.cpp
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "rwbase.h"
|
||||||
|
#include "rwerror.h"
|
||||||
|
#include "rwplg.h"
|
||||||
|
#include "rwpipeline.h"
|
||||||
|
#include "rwobjects.h"
|
||||||
|
#include "rwplugins.h"
|
||||||
|
#include "ps2/rwps2.h"
|
||||||
|
#include "ps2/rwps2plg.h"
|
||||||
|
#include "d3d/rwxbox.h"
|
||||||
|
#include "d3d/rwd3d8.h"
|
||||||
|
#include "d3d/rwd3d9.h"
|
||||||
|
#include "gl/rwwdgl.h"
|
||||||
|
#include "gl/rwgl3.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID ID_MATFX
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
|
||||||
|
// Atomic
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if(*PLUGINOFFSET(int32, src, offset))
|
||||||
|
MatFX::enableEffects((Atomic*)dst);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
readAtomicMatFX(Stream *stream, int32, void *object, int32, int32)
|
||||||
|
{
|
||||||
|
if(stream->readI32())
|
||||||
|
MatFX::enableEffects((Atomic*)object);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
writeAtomicMatFX(Stream *stream, int32, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
stream->writeI32(*PLUGINOFFSET(int32, object, offset));
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
getSizeAtomicMatFX(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
int32 flag = *PLUGINOFFSET(int32, object, offset);
|
||||||
|
// TODO: not sure which version
|
||||||
|
return flag || rw::version < 0x34000 ? 4 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Material
|
||||||
|
|
||||||
|
MatFXGlobals matFXGlobals = { 0, 0, { nil } };
|
||||||
|
|
||||||
|
// 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->destroy();
|
||||||
|
if(matfx->fx[i].bump.tex)
|
||||||
|
matfx->fx[i].bump.tex->destroy();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatFX::ENVMAP:
|
||||||
|
if(matfx->fx[i].env.tex)
|
||||||
|
matfx->fx[i].env.tex->destroy();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatFX::DUAL:
|
||||||
|
if(matfx->fx[i].dual.tex)
|
||||||
|
matfx->fx[i].dual.tex->destroy();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memset(matfx, 0, sizeof(MatFX));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setEffects(uint32 type)
|
||||||
|
{
|
||||||
|
if(this->type != 0 && this->type != type)
|
||||||
|
clearMatFX(this);
|
||||||
|
this->type = type;
|
||||||
|
switch(type){
|
||||||
|
case BUMPMAP:
|
||||||
|
case ENVMAP:
|
||||||
|
case DUAL:
|
||||||
|
case UVTRANSFORM:
|
||||||
|
this->fx[0].type = type;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
MatFX::getEffects(Material *m)
|
||||||
|
{
|
||||||
|
MatFX *fx = *PLUGINOFFSET(MatFX*, m, matFXGlobals.materialOffset);
|
||||||
|
if(fx)
|
||||||
|
return fx->type;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32
|
||||||
|
MatFX::getEffectIndex(uint32 type)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 2; i++)
|
||||||
|
if(this->fx[i].type == type)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setBumpTexture(Texture *t)
|
||||||
|
{
|
||||||
|
int32 i = this->getEffectIndex(BUMPMAP);
|
||||||
|
if(i >= 0)
|
||||||
|
this->fx[i].bump.tex = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setBumpCoefficient(float32 coef)
|
||||||
|
{
|
||||||
|
int32 i = this->getEffectIndex(BUMPMAP);
|
||||||
|
if(i >= 0)
|
||||||
|
this->fx[i].bump.coefficient = coef;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setEnvTexture(Texture *t)
|
||||||
|
{
|
||||||
|
int32 i = this->getEffectIndex(ENVMAP);
|
||||||
|
if(i >= 0)
|
||||||
|
this->fx[i].env.tex = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setEnvCoefficient(float32 coef)
|
||||||
|
{
|
||||||
|
int32 i = this->getEffectIndex(ENVMAP);
|
||||||
|
if(i >= 0)
|
||||||
|
this->fx[i].env.coefficient = coef;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setDualTexture(Texture *t)
|
||||||
|
{
|
||||||
|
int32 i = this->getEffectIndex(DUAL);
|
||||||
|
if(i >= 0)
|
||||||
|
this->fx[i].dual.tex = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setDualSrcBlend(int32 blend)
|
||||||
|
{
|
||||||
|
int32 i = this->getEffectIndex(DUAL);
|
||||||
|
if(i >= 0)
|
||||||
|
this->fx[i].dual.srcBlend = blend;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MatFX::setDualDestBlend(int32 blend)
|
||||||
|
{
|
||||||
|
int32 i = this->getEffectIndex(DUAL);
|
||||||
|
if(i >= 0)
|
||||||
|
this->fx[i].dual.dstBlend = blend;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
createMaterialMatFX(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
*PLUGINOFFSET(MatFX*, object, offset) = nil;
|
||||||
|
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 == nil)
|
||||||
|
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 Stream*
|
||||||
|
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 = nil;
|
||||||
|
if(stream->readI32()){
|
||||||
|
if(!findChunk(stream, ID_TEXTURE,
|
||||||
|
nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "TEXTURE"));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
bumpedTex = Texture::streamRead(stream);
|
||||||
|
}
|
||||||
|
if(stream->readI32()){
|
||||||
|
if(!findChunk(stream, ID_TEXTURE,
|
||||||
|
nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "TEXTURE"));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
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 = nil;
|
||||||
|
if(stream->readI32()){
|
||||||
|
if(!findChunk(stream, ID_TEXTURE,
|
||||||
|
nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "TEXTURE"));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
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 = nil;
|
||||||
|
if(stream->readI32()){
|
||||||
|
if(!findChunk(stream, ID_TEXTURE,
|
||||||
|
nil, nil)){
|
||||||
|
RWERROR((ERR_CHUNK, "TEXTURE"));
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
writeMaterialMatFX(Stream *stream, int32, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset);
|
||||||
|
|
||||||
|
stream->writeU32(matfx->type);
|
||||||
|
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 != nil);
|
||||||
|
if(matfx->fx[i].bump.bumpedTex)
|
||||||
|
matfx->fx[i].bump.bumpedTex->streamWrite(stream);
|
||||||
|
stream->writeI32(matfx->fx[i].bump.tex != nil);
|
||||||
|
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 != nil);
|
||||||
|
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 != nil);
|
||||||
|
if(matfx->fx[i].dual.tex)
|
||||||
|
matfx->fx[i].dual.tex->streamWrite(stream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
getSizeMaterialMatFX(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
MatFX *matfx = *PLUGINOFFSET(MatFX*, object, offset);
|
||||||
|
if(matfx == nil)
|
||||||
|
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
|
||||||
|
MatFX::enableEffects(Atomic *atomic)
|
||||||
|
{
|
||||||
|
*PLUGINOFFSET(int32, atomic, matFXGlobals.atomicOffset) = 1;
|
||||||
|
atomic->pipeline = matFXGlobals.pipelines[rw::platform];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerMatFXPlugin(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *defpipe = new ObjPipeline(PLATFORM_NULL);
|
||||||
|
defpipe->pluginID = 0; //ID_MATFX;
|
||||||
|
defpipe->pluginData = 0;
|
||||||
|
for(uint i = 0; i < nelem(matFXGlobals.pipelines); i++)
|
||||||
|
matFXGlobals.pipelines[i] = defpipe;
|
||||||
|
matFXGlobals.pipelines[PLATFORM_PS2] =
|
||||||
|
ps2::makeMatFXPipeline();
|
||||||
|
matFXGlobals.pipelines[PLATFORM_XBOX] =
|
||||||
|
xbox::makeMatFXPipeline();
|
||||||
|
matFXGlobals.pipelines[PLATFORM_D3D8] =
|
||||||
|
d3d8::makeMatFXPipeline();
|
||||||
|
matFXGlobals.pipelines[PLATFORM_D3D9] =
|
||||||
|
d3d9::makeMatFXPipeline();
|
||||||
|
matFXGlobals.pipelines[PLATFORM_WDGL] =
|
||||||
|
wdgl::makeMatFXPipeline();
|
||||||
|
matFXGlobals.pipelines[PLATFORM_GL3] =
|
||||||
|
gl3::makeMatFXPipeline();
|
||||||
|
|
||||||
|
matFXGlobals.atomicOffset =
|
||||||
|
Atomic::registerPlugin(sizeof(int32), ID_MATFX,
|
||||||
|
createAtomicMatFX, nil, copyAtomicMatFX);
|
||||||
|
Atomic::registerPluginStream(ID_MATFX,
|
||||||
|
readAtomicMatFX,
|
||||||
|
writeAtomicMatFX,
|
||||||
|
getSizeAtomicMatFX);
|
||||||
|
|
||||||
|
matFXGlobals.materialOffset =
|
||||||
|
Material::registerPlugin(sizeof(MatFX*), ID_MATFX,
|
||||||
|
createMaterialMatFX, destroyMaterialMatFX,
|
||||||
|
copyMaterialMatFX);
|
||||||
|
Material::registerPluginStream(ID_MATFX,
|
||||||
|
readMaterialMatFX,
|
||||||
|
writeMaterialMatFX,
|
||||||
|
getSizeMaterialMatFX);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1262
src/plugins.cpp
1262
src/plugins.cpp
File diff suppressed because it is too large
Load Diff
342
src/skin.cpp
Normal file
342
src/skin.cpp
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "rwbase.h"
|
||||||
|
#include "rwerror.h"
|
||||||
|
#include "rwplg.h"
|
||||||
|
#include "rwpipeline.h"
|
||||||
|
#include "rwobjects.h"
|
||||||
|
#include "rwplugins.h"
|
||||||
|
#include "ps2/rwps2.h"
|
||||||
|
#include "ps2/rwps2plg.h"
|
||||||
|
#include "d3d/rwxbox.h"
|
||||||
|
#include "d3d/rwd3d8.h"
|
||||||
|
#include "d3d/rwd3d9.h"
|
||||||
|
#include "gl/rwwdgl.h"
|
||||||
|
#include "gl/rwgl3.h"
|
||||||
|
|
||||||
|
#define PLUGIN_ID ID_SKIN
|
||||||
|
|
||||||
|
namespace rw {
|
||||||
|
|
||||||
|
SkinGlobals skinGlobals = { 0, { nil } };
|
||||||
|
|
||||||
|
static void*
|
||||||
|
createSkin(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
*PLUGINOFFSET(Skin*, object, offset) = nil;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
destroySkin(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
||||||
|
if(skin){
|
||||||
|
delete[] skin->data;
|
||||||
|
// delete[] skin->platformData;
|
||||||
|
}
|
||||||
|
delete skin;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
copySkin(void *dst, void *src, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Skin *srcskin = *PLUGINOFFSET(Skin*, src, offset);
|
||||||
|
if(srcskin == nil)
|
||||||
|
return dst;
|
||||||
|
Geometry *geometry = (Geometry*)src;
|
||||||
|
assert(geometry->instData == nil);
|
||||||
|
assert(((Geometry*)src)->numVertices == ((Geometry*)dst)->numVertices);
|
||||||
|
Skin *dstskin = new Skin;
|
||||||
|
*PLUGINOFFSET(Skin*, dst, offset) = dstskin;
|
||||||
|
dstskin->numBones = srcskin->numBones;
|
||||||
|
dstskin->numUsedBones = srcskin->numUsedBones;
|
||||||
|
dstskin->numWeights = srcskin->numWeights;
|
||||||
|
|
||||||
|
assert(0 && "can't copy skin yet");
|
||||||
|
dstskin->init(srcskin->numBones, srcskin->numUsedBones, 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);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
readSkin(Stream *stream, int32 len, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
uint8 header[4];
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
|
||||||
|
if(geometry->instData){
|
||||||
|
// TODO: function pointers
|
||||||
|
if(geometry->instData->platform == PLATFORM_PS2)
|
||||||
|
return ps2::readNativeSkin(stream, len, object, offset);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_WDGL)
|
||||||
|
return wdgl::readNativeSkin(stream, len, object, offset);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_XBOX)
|
||||||
|
return xbox::readNativeSkin(stream, len, object, offset);
|
||||||
|
else{
|
||||||
|
assert(0 && "unsupported native skin platform");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->read(header, 4); // numBones, numUsedBones, numWeights, unused
|
||||||
|
Skin *skin = new Skin;
|
||||||
|
*PLUGINOFFSET(Skin*, geometry, offset) = skin;
|
||||||
|
|
||||||
|
// numUsedBones and numWeights appear in/after 34003 but not in/before 33002
|
||||||
|
// (probably rw::version >= 0x34000)
|
||||||
|
bool oldFormat = header[1] == 0;
|
||||||
|
|
||||||
|
// Use numBones for numUsedBones to allocate data, find out the correct value later
|
||||||
|
if(oldFormat)
|
||||||
|
skin->init(header[0], header[0], geometry->numVertices);
|
||||||
|
else
|
||||||
|
skin->init(header[0], header[1], geometry->numVertices);
|
||||||
|
skin->numWeights = header[2];
|
||||||
|
|
||||||
|
if(!oldFormat)
|
||||||
|
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);
|
||||||
|
|
||||||
|
//{
|
||||||
|
//float *mat = &skin->inverseMatrices[i*16];
|
||||||
|
//printf("[ [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
|
||||||
|
// " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
|
||||||
|
// " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n"
|
||||||
|
// " [ %8.4f, %8.4f, %8.4f, %8.4f ] ]\n",
|
||||||
|
// mat[0], mat[4], mat[8], mat[12],
|
||||||
|
// mat[1], mat[5], mat[9], mat[13],
|
||||||
|
// mat[2], mat[6], mat[10], mat[14],
|
||||||
|
// mat[3], mat[7], mat[11], mat[15]);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oldFormat){
|
||||||
|
skin->findNumWeights(geometry->numVertices);
|
||||||
|
skin->findUsedBones(geometry->numVertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no split skins in GTA
|
||||||
|
if(!oldFormat)
|
||||||
|
stream->seek(12);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream*
|
||||||
|
writeSkin(Stream *stream, int32 len, void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
uint8 header[4];
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
|
||||||
|
if(geometry->instData){
|
||||||
|
if(geometry->instData->platform == PLATFORM_PS2)
|
||||||
|
ps2::writeNativeSkin(stream, len, object, offset);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_WDGL)
|
||||||
|
wdgl::writeNativeSkin(stream, len, object, offset);
|
||||||
|
else if(geometry->instData->platform == PLATFORM_XBOX)
|
||||||
|
xbox::writeNativeSkin(stream, len, object, offset);
|
||||||
|
else{
|
||||||
|
assert(0 && "unsupported native skin platform");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
||||||
|
// not sure which version introduced the new format
|
||||||
|
bool oldFormat = version < 0x34000;
|
||||||
|
header[0] = skin->numBones;
|
||||||
|
if(oldFormat){
|
||||||
|
header[1] = 0;
|
||||||
|
header[2] = 0;
|
||||||
|
}else{
|
||||||
|
header[1] = skin->numUsedBones;
|
||||||
|
header[2] = skin->numWeights;
|
||||||
|
}
|
||||||
|
header[3] = 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no split skins in GTA
|
||||||
|
if(!oldFormat){
|
||||||
|
uint32 buffer[3] = { 0, 0, 0};
|
||||||
|
stream->write(buffer, 12);
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32
|
||||||
|
getSizeSkin(void *object, int32 offset, int32)
|
||||||
|
{
|
||||||
|
Geometry *geometry = (Geometry*)object;
|
||||||
|
|
||||||
|
if(geometry->instData){
|
||||||
|
if(geometry->instData->platform == PLATFORM_PS2)
|
||||||
|
return ps2::getSizeNativeSkin(object, offset);
|
||||||
|
if(geometry->instData->platform == PLATFORM_WDGL)
|
||||||
|
return wdgl::getSizeNativeSkin(object, offset);
|
||||||
|
if(geometry->instData->platform == PLATFORM_XBOX)
|
||||||
|
return xbox::getSizeNativeSkin(object, offset);
|
||||||
|
if(geometry->instData->platform == PLATFORM_D3D8)
|
||||||
|
return -1;
|
||||||
|
if(geometry->instData->platform == PLATFORM_D3D9)
|
||||||
|
return -1;
|
||||||
|
assert(0 && "unsupported native skin platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
Skin *skin = *PLUGINOFFSET(Skin*, object, offset);
|
||||||
|
if(skin == nil)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int32 size = 4 + geometry->numVertices*(16+4) +
|
||||||
|
skin->numBones*64;
|
||||||
|
// not sure which version introduced the new format
|
||||||
|
if(version < 0x34000)
|
||||||
|
size += skin->numBones*4;
|
||||||
|
else
|
||||||
|
size += skin->numUsedBones + 12;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
skinRights(void *object, int32, int32, uint32)
|
||||||
|
{
|
||||||
|
Skin::setPipeline((Atomic*)object, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
registerSkinPlugin(void)
|
||||||
|
{
|
||||||
|
ObjPipeline *defpipe = new ObjPipeline(PLATFORM_NULL);
|
||||||
|
defpipe->pluginID = ID_SKIN;
|
||||||
|
defpipe->pluginData = 1;
|
||||||
|
for(uint i = 0; i < nelem(skinGlobals.pipelines); i++)
|
||||||
|
skinGlobals.pipelines[i] = defpipe;
|
||||||
|
skinGlobals.pipelines[PLATFORM_PS2] =
|
||||||
|
ps2::makeSkinPipeline();
|
||||||
|
skinGlobals.pipelines[PLATFORM_XBOX] =
|
||||||
|
xbox::makeSkinPipeline();
|
||||||
|
skinGlobals.pipelines[PLATFORM_D3D8] =
|
||||||
|
d3d8::makeSkinPipeline();
|
||||||
|
skinGlobals.pipelines[PLATFORM_D3D9] =
|
||||||
|
d3d9::makeSkinPipeline();
|
||||||
|
skinGlobals.pipelines[PLATFORM_WDGL] =
|
||||||
|
wdgl::makeSkinPipeline();
|
||||||
|
skinGlobals.pipelines[PLATFORM_GL3] =
|
||||||
|
gl3::makeSkinPipeline();
|
||||||
|
|
||||||
|
skinGlobals.offset = Geometry::registerPlugin(sizeof(Skin*), ID_SKIN,
|
||||||
|
createSkin,
|
||||||
|
destroySkin,
|
||||||
|
copySkin);
|
||||||
|
Geometry::registerPluginStream(ID_SKIN,
|
||||||
|
readSkin, writeSkin, getSizeSkin);
|
||||||
|
Atomic::registerPlugin(0, ID_SKIN, nil, nil, nil);
|
||||||
|
Atomic::setStreamRightsCallback(ID_SKIN, skinRights);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Skin::init(int32 numBones, int32 numUsedBones, int32 numVertices)
|
||||||
|
{
|
||||||
|
this->numBones = numBones;
|
||||||
|
this->numUsedBones = numUsedBones;
|
||||||
|
uint32 size = this->numUsedBones +
|
||||||
|
this->numBones*64 +
|
||||||
|
numVertices*(16+4) + 0xF;
|
||||||
|
this->data = new uint8[size];
|
||||||
|
uint8 *p = this->data;
|
||||||
|
|
||||||
|
this->usedBones = nil;
|
||||||
|
if(this->numUsedBones){
|
||||||
|
this->usedBones = p;
|
||||||
|
p += this->numUsedBones;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = (uint8*)(((uintptr)p + 0xF) & ~0xF);
|
||||||
|
this->inverseMatrices = nil;
|
||||||
|
if(this->numBones){
|
||||||
|
this->inverseMatrices = (float*)p;
|
||||||
|
p += 64*this->numBones;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->indices = nil;
|
||||||
|
if(numVertices){
|
||||||
|
this->indices = p;
|
||||||
|
p += 4*numVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->weights = nil;
|
||||||
|
if(numVertices)
|
||||||
|
this->weights = (float*)p;
|
||||||
|
|
||||||
|
this->platformData = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Skin::findNumWeights(int32 numVertices)
|
||||||
|
{
|
||||||
|
this->numWeights = 1;
|
||||||
|
float *w = this->weights;
|
||||||
|
while(numVertices--){
|
||||||
|
while(w[this->numWeights] != 0.0f){
|
||||||
|
this->numWeights++;
|
||||||
|
if(this->numWeights == 4)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Skin::findUsedBones(int32 numVertices)
|
||||||
|
{
|
||||||
|
uint8 usedTab[256];
|
||||||
|
uint8 *indices = this->indices;
|
||||||
|
float *weights = this->weights;
|
||||||
|
memset(usedTab, 0, 256);
|
||||||
|
while(numVertices--){
|
||||||
|
for(int32 i = 0; i < this->numWeights; i++){
|
||||||
|
if(weights[i] == 0.0f)
|
||||||
|
continue; // TODO: this could probably be optimized
|
||||||
|
if(usedTab[indices[i]] == 0)
|
||||||
|
usedTab[indices[i]]++;
|
||||||
|
}
|
||||||
|
indices += 4;
|
||||||
|
weights += 4;
|
||||||
|
}
|
||||||
|
this->numUsedBones = 0;
|
||||||
|
for(int32 i = 0; i < 256; i++)
|
||||||
|
if(usedTab[i])
|
||||||
|
this->usedBones[this->numUsedBones++] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Skin::setPipeline(Atomic *a, int32 type)
|
||||||
|
{
|
||||||
|
(void)type;
|
||||||
|
a->pipeline = skinGlobals.pipelines[rw::platform];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user