userdata changes; hanim fixes; support for reading old skins

This commit is contained in:
aap 2020-08-06 09:14:32 +02:00
parent 26a5502ee1
commit 171e737842
8 changed files with 115 additions and 35 deletions

View File

@ -132,7 +132,7 @@ Animation::streamReadLegacy(Stream *stream)
stream->read32(&frames[i].t, 3*4);
frames[i].time = stream->readF32();
int32 prev = stream->readI32();
frames[i].prevFrame = &frames[prev];
frames[i].prev = &frames[prev];
}
return anim;
}
@ -162,7 +162,7 @@ Animation::streamWriteLegacy(Stream *stream)
stream->write32(&frames[i].q, 4*4);
stream->write32(&frames[i].t, 3*4);
stream->writeF32(frames[i].time);
stream->writeI32(frames[i].prevFrame - frames);
stream->writeI32(frames[i].prev - frames);
}
return true;
}

View File

@ -488,8 +488,10 @@ Matrix::lookAt(const V3d &dir, const V3d &up)
this->flags = TYPEORTHONORMAL;
}
/* For a row-major representation, this calculates src1 * src.
* For colum-major src2 * src1 */
/* For a row-major representation, this calculates src1 * src2.
* For column-major src2 * src1.
* i.e. a vector is first xformed by src1, then by src2
*/
void
Matrix::mult_(Matrix *dst, const Matrix *src1, const Matrix *src2)
{

View File

@ -102,7 +102,8 @@ HAnimHierarchy::attachByIndex(int32 idx)
int32 id = this->nodeInfo[idx].id;
// Frame *f = findById(this->parentFrame, id);
Frame *f = findUnattachedById(this, this->parentFrame, id);
this->nodeInfo[idx].frame = f;
if(f)
this->nodeInfo[idx].frame = f;
}
void
@ -172,8 +173,13 @@ HAnimHierarchy::updateMatrices(void)
HAnimNodeInfo *node = this->nodeInfo;
for(i = 0; i < this->numNodes; i++){
anim->applyCB(&animMat, anim->getInterpFrame(i));
// TODO: here we could update local matrices
Matrix::mult(curMat, &animMat, parentMat);
// TODO: here we could update LTM
if(node->flags & PUSH)
*sp++ = parentMat;
parentMat = curMat;
@ -317,7 +323,7 @@ hAnimFrameRead(Stream *stream, Animation *anim)
stream->read32(&frames[i].q, 4*4);
stream->read32(&frames[i].t, 3*4);
int32 prev = stream->readI32()/0x24;
frames[i].prevFrame = &frames[prev];
frames[i].prev = &frames[prev];
}
}
@ -329,7 +335,7 @@ hAnimFrameWrite(Stream *stream, Animation *anim)
stream->writeF32(frames[i].time);
stream->write32(&frames[i].q, 4*4);
stream->write32(&frames[i].t, 3*4);
stream->writeI32((frames[i].prevFrame - frames)*0x24);
stream->writeI32((frames[i].prev - frames)*0x24);
}
}

View File

@ -63,6 +63,10 @@ struct Animation
int32 flags, float duration);
void destroy(void);
int32 getNumNodes(void);
KeyFrameHeader *getAnimFrame(int32 n){
return (KeyFrameHeader*)((uint8*)this->keyframes +
n*this->interpInfo->animKeyFrameSize);
}
static Animation *streamRead(Stream *stream);
static Animation *streamReadLegacy(Stream *stream);
bool streamWrite(Stream *stream);

View File

@ -6,7 +6,7 @@ namespace rw {
struct HAnimKeyFrame
{
HAnimKeyFrame *prevFrame;
HAnimKeyFrame *prev;
float32 time;
Quat q;
V3d t;

View File

@ -64,7 +64,18 @@ struct UserDataExtension
int32 numArrays;
UserDataArray *arrays;
// TODO: static accessors
int32 add(const char *name, int32 datatype, int32 numElements);
void remove(int32 n);
int32 getCount(void) { return numArrays; }
UserDataArray *get(int32 n) { return n >= numArrays ? nil : &arrays[n]; }
int32 findIndex(const char *name);
static UserDataExtension *get(Geometry *geo);
static UserDataExtension *get(Frame *frame);
static UserDataExtension *get(Camera *cam);
static UserDataExtension *get(Light *light);
static UserDataExtension *get(Material *mat);
static UserDataExtension *get(Texture *tex);
};
struct UserDataGlobals

View File

@ -252,6 +252,55 @@ getSizeSkin(void *object, int32 offset, int32)
return size;
}
static Stream*
readSkinLegacy(Stream *stream, int32 len, void *object, int32, int32)
{
Atomic *atomic = (Atomic*)object;
Geometry *geometry = atomic->geometry;
int32 numBones = stream->readI32();
int32 numVertices = stream->readI32();
assert(numVertices == geometry->numVertices);
Skin *skin = rwNewT(Skin, 1, MEMDUR_EVENT | ID_SKIN);
*PLUGINOFFSET(Skin*, geometry, skinGlobals.geoOffset) = skin;
skin->init(numBones, numBones, numVertices);
skin->numWeights = 4;
stream->read8(skin->indices, numVertices*4);
stream->read32(skin->weights, numVertices*16);
HAnimHierarchy *hier = HAnimHierarchy::create(numBones, nil, nil, 0, 36);
for(int i = 0; i < numBones; i++){
hier->nodeInfo[i].id = stream->readI32();
hier->nodeInfo[i].index = stream->readI32();
hier->nodeInfo[i].flags = stream->readI32() & 3;
// printf("%d %d %d %d\n", i, hier->nodeInfo[i].id, hier->nodeInfo[i].index, hier->nodeInfo[i].flags);
stream->read32(&skin->inverseMatrices[i*16], 64);
Matrix mat;
Matrix::invert(&mat, (Matrix*)&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"
// " %08x == flags\n",
// mat.right.x, mat.up.x, mat.at.x, mat.pos.x,
// mat.right.y, mat.up.y, mat.at.y, mat.pos.y,
// mat.right.z, mat.up.z, mat.at.z, mat.pos.z,
// 0.0f, 0.0f, 0.0f, 1.0f,
// mat.flags);
}
Frame *frame = atomic->getFrame()->child;
assert(frame->next == nil); // in old files atomic is above hierarchy it seems
assert(frame->count() == numBones); // assuming one frame per node this should also be true
HAnimData::get(frame)->hierarchy = hier;
hier->parentFrame = frame;
return stream;
}
static void
skinRights(void *object, int32, int32, uint32)
{
@ -317,6 +366,7 @@ registerSkinPlugin(void)
o = Atomic::registerPlugin(sizeof(HAnimHierarchy*),ID_SKIN,
createSkinAtm, destroySkinAtm, copySkinAtm);
skinGlobals.atomicOffset = o;
Atomic::registerPluginStream(ID_SKIN, readSkinLegacy, nil, nil);
Atomic::setStreamRightsCallback(ID_SKIN, skinRights);
}

View File

@ -226,27 +226,27 @@ getSizeUserData(void *object, int32 offset, int32)
return size;
}
static int32
add(UserDataExtension *ext, const char *name, int32 datatype, int32 numElements)
int32
UserDataExtension::add(const char *name, int32 datatype, int32 numElements)
{
int32 i;
int32 len;
int32 typesz;
UserDataArray *a;
// try to find empty slot
for(i = 0; i < ext->numArrays; i++)
if(ext->arrays[i].datatype == USERDATANA)
for(i = 0; i < this->numArrays; i++)
if(this->arrays[i].datatype == USERDATANA)
goto alloc;
// have to realloc
a = (UserDataArray*)udMalloc((ext->numArrays+1)*sizeof(UserDataArray));
a = (UserDataArray*)udMalloc((this->numArrays+1)*sizeof(UserDataArray));
if(a == nil)
return -1;
memcpy(a, ext->arrays, ext->numArrays*sizeof(UserDataArray));
rwFree(ext->arrays);
ext->arrays = a;
i = ext->numArrays++;
memcpy(a, this->arrays, this->numArrays*sizeof(UserDataArray));
rwFree(this->arrays);
this->arrays = a;
i = this->numArrays++;
alloc:
a = &ext->arrays[i];
a = &this->arrays[i];
len = (int32)strlen(name)+1;
a->name = (char*)udMalloc(len+1);
assert(a->name);
@ -262,11 +262,11 @@ alloc:
return i;
}
static void
remove(UserDataExtension *ext, int32 n)
void
UserDataExtension::remove(int32 n)
{
int32 i;
UserDataArray *a = &ext->arrays[n];
UserDataArray *a = &this->arrays[n];
if(a->name){
rwFree(a->name);
a->name = nil;
@ -282,39 +282,39 @@ remove(UserDataExtension *ext, int32 n)
a->numElements = 0;
}
int32
UserDataExtension::findIndex(const char *name) {
for(int32 i = 0; i < this->numArrays; i++)
if(strcmp(this->arrays[i].name, name) == 0)
return i;
return -1;
}
#define ACCESSOR(TYPE, NAME) \
int32 \
UserDataArray::NAME##Add(TYPE *t, const char *name, int32 datatype, int32 numElements) \
{ \
return add(PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset), \
name, datatype, numElements); \
return PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->add(name, datatype, numElements); \
} \
void \
UserDataArray::NAME##Remove(TYPE *t, int32 n) \
{ \
remove(PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset), n); \
PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->remove(n); \
} \
int32 \
UserDataArray::NAME##GetCount(TYPE *t) \
{ \
return PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->numArrays; \
return PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->getCount(); \
} \
UserDataArray* \
UserDataArray::NAME##Get(TYPE *t, int32 n) \
{ \
if(n >= PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->numArrays) \
return nil; \
return &PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->arrays[n]; \
return PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->get(n); \
} \
int32 \
UserDataArray::NAME##FindIndex(TYPE *t, const char *name) \
{ \
int32 i; \
UserDataExtension *ext = PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset); \
for(i = 0; i < ext->numArrays; i++) \
if(strcmp(ext->arrays[i].name, name) == 0) \
return i; \
return -1; \
return PLUGINOFFSET(UserDataExtension, t, userDataGlobals.NAME##Offset)->findIndex(name); \
}
ACCESSOR(Geometry, geometry)
@ -324,6 +324,13 @@ ACCESSOR(Light, light)
ACCESSOR(Material, material)
ACCESSOR(Texture, texture)
UserDataExtension *UserDataExtension::get(Geometry *geo) { return PLUGINOFFSET(UserDataExtension, geo, userDataGlobals.geometryOffset); }
UserDataExtension *UserDataExtension::get(Frame *frame) { return PLUGINOFFSET(UserDataExtension, frame, userDataGlobals.frameOffset); }
UserDataExtension *UserDataExtension::get(Camera *cam) { return PLUGINOFFSET(UserDataExtension, cam, userDataGlobals.cameraOffset); }
UserDataExtension *UserDataExtension::get(Light *light) { return PLUGINOFFSET(UserDataExtension, light, userDataGlobals.lightOffset); }
UserDataExtension *UserDataExtension::get(Material *mat) { return PLUGINOFFSET(UserDataExtension, mat, userDataGlobals.materialOffset); }
UserDataExtension *UserDataExtension::get(Texture *tex) { return PLUGINOFFSET(UserDataExtension, tex, userDataGlobals.textureOffset); }
void
registerUserDataPlugin(void)
{