mirror of
https://github.com/ptitSeb/Serious-Engine
synced 2024-11-28 21:05:53 +01:00
883 lines
20 KiB
C++
883 lines
20 KiB
C++
/* Copyright (c) 2002-2012 Croteam Ltd.
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of version 2 of the GNU General Public License as published by
|
|
the Free Software Foundation
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
#include <lwsurf.h>
|
|
#include <lwhost.h>
|
|
#include <lwserver.h>
|
|
#include <lwgeneric.h>
|
|
#include <crtdbg.h>
|
|
#include <stdarg.h>
|
|
#include "vecmat.h"
|
|
#include <crtdbg.h>
|
|
|
|
#include <lwserver.h>
|
|
#include <lwmotion.h>
|
|
#include <lwxpanel.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include "base.h"
|
|
|
|
static int _iFrame = 0;
|
|
static int _ctFrames = 0;
|
|
static int _ctBones = 0;
|
|
static int ctBoneEnvelopes = 0;
|
|
static int ctMorphEnvelopes = 0;
|
|
static LWItemID idMasterObjID = 0;
|
|
|
|
extern bool bRecordDefaultFrame;
|
|
extern int ReloadGlobalObjects();
|
|
extern bool bExportAbsPositions; // export first bone absolute position
|
|
typedef float Matrix12[12];
|
|
|
|
|
|
|
|
static int _ctNumBones;
|
|
static FILE *_f = NULL;
|
|
static char *_strFileName = NULL;
|
|
|
|
static BoneInfo *_pbiFirst = NULL; // linked list of all instances
|
|
static MorphInfo *_pmiFirst = NULL; // linked list of all instances
|
|
static Matrix12 *_pmRootBoneAbs=NULL;
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Create()
|
|
|
|
Handler callback. Allocate and initialize instance data.
|
|
====================================================================== */
|
|
XCALL_( static LWInstance )
|
|
Create( void *priv, LWItemID item, LWError *err )
|
|
{
|
|
// create the instance
|
|
BoneInfo *pii = (BoneInfo*)malloc(sizeof(BoneInfo));
|
|
pii->bi_strName = strdup(_iti->name(item));
|
|
|
|
_ctBones++;
|
|
|
|
// get parent bone name
|
|
LWItemID pParentID = _iti->parent(item);
|
|
//strdup()
|
|
pii->bi_strParentName = strdup(_iti->name(pParentID));
|
|
if(pParentID == LWITEM_NULL) {
|
|
// this is root bone
|
|
pii->bi_strParentName = "";
|
|
}
|
|
// get item type
|
|
pii->bi_lwItemType = _iti->type(item);
|
|
|
|
// allocate space for storing frames
|
|
pii->bi_abfFrames = (BoneFrame*)malloc(sizeof(BoneFrame)*_ctFrames);
|
|
|
|
// if first time here
|
|
/* if(_pbiFirst==NULL)
|
|
{
|
|
// allocate space for storing absolute position for root bone
|
|
_pmRootBoneAbs = (Matrix12*)malloc(sizeof(Matrix12)*_ctFrames);
|
|
for(int ifr=0;ifr<_ctFrames;ifr++)
|
|
{
|
|
// reset matrices of root bone for all frames
|
|
MakeIdentityMatrix(_pmRootBoneAbs[ifr]);
|
|
int a=0;
|
|
}
|
|
}
|
|
*/
|
|
// link into list
|
|
pii->bi_pbiNext = _pbiFirst;
|
|
|
|
_pbiFirst = pii;
|
|
return pii;
|
|
};
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Destroy()
|
|
|
|
Handler callback. Free resources allocated by Create().
|
|
====================================================================== */
|
|
|
|
XCALL_( static void )
|
|
Destroy( BoneInfo *inst)
|
|
{
|
|
free(inst);
|
|
//free(_pmRootBoneAbs);
|
|
}
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Copy()
|
|
|
|
Handler callback. Copy instance data.
|
|
====================================================================== */
|
|
|
|
XCALL_( static LWError )
|
|
Copy( BoneInfo *to, BoneInfo *from )
|
|
{
|
|
*to = *from;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Load()
|
|
|
|
Handler callback. Read instance data.
|
|
====================================================================== */
|
|
|
|
XCALL_( static LWError )
|
|
Load( BoneInfo *inst, const LWLoadState *ls )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Save()
|
|
|
|
Handler callback. Write instance data.
|
|
====================================================================== */
|
|
|
|
XCALL_( static LWError )
|
|
Save( BoneInfo *inst, const LWSaveState *ss )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Describe()
|
|
|
|
Handler callback. Write a short, human-readable string describing
|
|
the instance data.
|
|
====================================================================== */
|
|
|
|
XCALL_( static const char * )
|
|
Describe( BoneInfo *inst )
|
|
{
|
|
static char desc[ 80 ];
|
|
sprintf( desc, "SE Sections Motion Export Handler");
|
|
return desc;
|
|
}
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Flags()
|
|
|
|
Handler callback.
|
|
====================================================================== */
|
|
|
|
XCALL_( static int )
|
|
Flags( BoneInfo *inst )
|
|
{
|
|
return LWIMF_AFTERIK;
|
|
}
|
|
|
|
|
|
/*
|
|
======================================================================
|
|
Evaluate()
|
|
|
|
Handler callback. This is where we can modify the item's motion.
|
|
====================================================================== */
|
|
|
|
XCALL_( static void )
|
|
Evaluate( BoneInfo *pii, const LWItemMotionAccess *access )
|
|
{
|
|
LWItemID parentID,parentparentID;
|
|
double pos[3], rot[3];
|
|
double dvParentPos[3] = {0,0,0};
|
|
double dvParentRot[3] = {0,0,0};
|
|
|
|
|
|
access->getParam( LWIP_POSITION, access->time, pos);
|
|
access->getParam( LWIP_ROTATION, access->time, rot);
|
|
parentID = _iti->parent(access->item);
|
|
|
|
|
|
LWItemID bone = access->item;
|
|
|
|
if (access->item != idMasterObjID) {
|
|
parentID = _iti->parent(bone);
|
|
|
|
_pmesh = _obi->meshInfo(parentID, 0);
|
|
if (_pmesh != NULL) {
|
|
parentparentID = _iti->parent(parentID);
|
|
|
|
_pmesh = _obi->meshInfo(parentparentID, 0);
|
|
if (_pmesh == NULL) {
|
|
_iti->param(parentparentID,LWIP_POSITION,0,dvParentPos);
|
|
} else {
|
|
_iti->param(parentID,LWIP_POSITION,0,dvParentPos);
|
|
}
|
|
} else {
|
|
parentparentID = _iti->parent(parentID);
|
|
|
|
_pmesh = _obi->meshInfo(parentparentID, 0);
|
|
if (_pmesh == NULL) {
|
|
_iti->param(parentID,LWIP_POSITION,0,dvParentPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pii->bi_abfFrames[_iFrame].fi_vPos[0] = (float)(pos[0] - dvParentPos[0]);
|
|
pii->bi_abfFrames[_iFrame].fi_vPos[1] = (float)(pos[1] - dvParentPos[1]);
|
|
pii->bi_abfFrames[_iFrame].fi_vPos[2] = (float)(pos[2] - dvParentPos[2]);
|
|
pii->bi_abfFrames[_iFrame].fi_vRot[0] = (float)(rot[0] - dvParentRot[0]);
|
|
pii->bi_abfFrames[_iFrame].fi_vRot[1] = (float)(rot[1] - dvParentRot[1]);
|
|
pii->bi_abfFrames[_iFrame].fi_vRot[2] = (float)(rot[2] - dvParentRot[2]);
|
|
|
|
/*// get pivot position
|
|
_iti->param(bone,LWIP_PIVOT,access->time,pivotpos);
|
|
_iti->param(bone,LWIP_PIVOT_ROT,access->time,pivotrot);
|
|
float fPivotPos[3], fPivotRot[3];
|
|
for(int ia=0;ia<3;ia++)
|
|
{
|
|
fPivotPos[ia] = (float)pivotpos[ia];
|
|
fPivotRot[ia] = (float)pivotrot[ia];
|
|
}
|
|
fPivotPos[2] *=-1;
|
|
pii->bi_abfFrames[_iFrame].fi_vPos[2] *=-1;
|
|
|
|
// get object pivot matix
|
|
Matrix12 mPivot,mPivotInvert;
|
|
MakeRotationAndPosMatrix(mPivot,fPivotPos,fPivotRot);
|
|
MatrixTranspose(mPivotInvert,mPivot);
|
|
// get object matrix
|
|
Matrix12 mTemp,mObject;
|
|
MakeRotationAndPosMatrix(mObject,&pii->bi_abfFrames[_iFrame].fi_vPos[0],&pii->bi_abfFrames[_iFrame].fi_vRot[0]);
|
|
MatrixCopy(mTemp,mObject);
|
|
MatrixMultiply(mObject,mTemp,mPivotInvert);
|
|
|
|
//MakeIdentityMatrix(mTemp);
|
|
//MatrixCopy(mTemp,mPivot);
|
|
|
|
// add its position and rotation to abs matrix
|
|
//MakeIdentityMatrix(mTemp);
|
|
MatrixCopy(mTemp,_pmRootBoneAbs[_iFrame]);
|
|
MatrixMultiply(_pmRootBoneAbs[_iFrame],mObject,mTemp);*/
|
|
pii->bi_abfFrames[_iFrame].fi_vPos[2] *=-1;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XCALL_( int )
|
|
SectionAnimation_Handler( long version, GlobalFunc *_global, LWItemMotionHandler *local,
|
|
void *serverData)
|
|
{
|
|
if ( version != LWITEMMOTION_VERSION ) return AFUNC_BADVERSION;
|
|
|
|
_iti = (LWItemInfo *)_global(LWITEMINFO_GLOBAL, GFUSE_TRANSIENT);
|
|
if (_iti==NULL) {
|
|
return AFUNC_BADGLOBAL;
|
|
}
|
|
|
|
local->inst->create = Create;
|
|
local->inst->destroy = (void (*)(void *))Destroy;
|
|
local->inst->load = (const char *(__cdecl *)(void *,const struct st_LWLoadState *))Load;
|
|
local->inst->save = (const char *(__cdecl *)(void *,const struct st_LWSaveState *))Save;
|
|
local->inst->copy = (const char *(__cdecl *)(void *,void *))Copy;
|
|
local->inst->descln = (const char *(__cdecl *)(void *))Describe;
|
|
local->evaluate = (void (__cdecl *)(void *,const struct st_LWItemMotionAccess *))Evaluate;
|
|
local->flags = (unsigned int (__cdecl *)(void *))Flags;
|
|
|
|
return AFUNC_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void AddBoneToCount(LWItemID objectid)
|
|
{
|
|
LWItemID childID;
|
|
|
|
childID = _iti->firstChild(objectid);
|
|
if(_iti->type(objectid) == LWI_OBJECT)
|
|
{
|
|
_pmesh = _obi->meshInfo(objectid, 0);
|
|
if((_pmesh == NULL) && (childID == LWITEM_NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_ctNumBones++;
|
|
|
|
while (childID != LWITEM_NULL) {
|
|
AddBoneToCount(childID);
|
|
childID = _iti->nextChild(objectid,childID);
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void WriteBoneInfo(LWItemID objectid)
|
|
{
|
|
LWItemID childID,parentID,parentparentID;
|
|
double dvPos[3],dvRot[3];
|
|
double dvParentPos[3] = {0,0,0};
|
|
double dvParentRot[3] = {0,0,0};
|
|
float fvPos[3],fvRot[3];
|
|
Matrix12 bi_mRot;
|
|
const char *strName, *strParentName;
|
|
float fLength = 0.5;
|
|
|
|
|
|
childID = _iti->firstChild(objectid);
|
|
if(_iti->type(objectid) == LWI_OBJECT)
|
|
{
|
|
|
|
_pmesh = _obi->meshInfo(objectid, 0);
|
|
if((_pmesh == NULL) && (childID == LWITEM_NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
_iti->param(objectid,LWIP_POSITION,0,dvPos);
|
|
_iti->param(objectid,LWIP_ROTATION,0,dvRot);
|
|
|
|
strName = _iti->name(objectid);
|
|
fprintf(_f, " NAME \"%s\";\n", strName);
|
|
if (_ctNumBones > 0) {
|
|
|
|
parentID = _iti->parent(objectid);
|
|
|
|
_pmesh = _obi->meshInfo(parentID, 0);
|
|
if (_pmesh != NULL) {
|
|
parentparentID = _iti->parent(parentID);
|
|
|
|
_pmesh = _obi->meshInfo(parentparentID, 0);
|
|
if (_pmesh == NULL) {
|
|
_iti->param(parentparentID,LWIP_POSITION,0,dvParentPos);
|
|
//_iti->param(parentparentID,LWIP_ROTATION,0,dvParentRot);
|
|
|
|
} else {
|
|
_iti->param(parentID,LWIP_POSITION,0,dvParentPos);
|
|
//_iti->param(parentID,LWIP_ROTATION,0,dvParentRot);
|
|
}
|
|
} else {
|
|
parentparentID = _iti->parent(parentID);
|
|
|
|
_pmesh = _obi->meshInfo(parentparentID, 0);
|
|
if (_pmesh == NULL) {
|
|
_iti->param(parentID,LWIP_POSITION,0,dvParentPos);
|
|
// _iti->param(parentID,LWIP_ROTATION,0,dvParentRot);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
strParentName = _iti->name(parentID);
|
|
} else {
|
|
strParentName = strdup("");
|
|
}
|
|
|
|
|
|
fprintf(_f, " PARENT \"%s\";\n", strParentName);
|
|
fprintf(_f, " LENGTH %g;\n", fLength);
|
|
fprintf(_f, " {\n");
|
|
|
|
for (int i=0;i<3;i++) {
|
|
fvPos[i] = (float) (dvPos[i] - dvParentPos[i]);
|
|
fvRot[i] = 0;//(float) (dvRot[i] - dvParentRot[i]);
|
|
}
|
|
fvPos[2] = -fvPos[2];
|
|
|
|
MakeRotationAndPosMatrix(bi_mRot,fvPos,fvRot);
|
|
PrintMatrix(_f,bi_mRot,4);
|
|
fprintf(_f,"\n }\n");
|
|
|
|
_ctNumBones++;
|
|
|
|
while (childID != LWITEM_NULL) {
|
|
WriteBoneInfo(childID);
|
|
childID = _iti->nextChild(objectid,childID);
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
bool AddMotionHandler(LWItemID objectid)
|
|
{
|
|
LWItemID childID;
|
|
|
|
childID = _iti->firstChild(objectid);
|
|
if(_iti->type(objectid) == LWI_OBJECT)
|
|
{
|
|
_pmesh = _obi->meshInfo(objectid, 0);
|
|
if((_pmesh == NULL) && (childID == LWITEM_NULL))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ExecCmd("SelectItem %x", objectid)) {
|
|
_msg->error("ERROR: Item selection\n", NULL);
|
|
return false;
|
|
}
|
|
if (!ExecCmd("ApplyServer ItemMotionHandler " DEBUGEXT "internal_SESectionAnimExport")) {
|
|
_msg->error("ERROR: Applying ItemMotionHandler\n", NULL);
|
|
return false;
|
|
}
|
|
|
|
while (childID != LWITEM_NULL) {
|
|
AddMotionHandler(childID);
|
|
childID = _iti->nextChild(objectid,childID);
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
int RemoveMotionHandler(LWItemID objectid)
|
|
{
|
|
LWItemID childID;
|
|
|
|
childID = _iti->firstChild(objectid);
|
|
if(_iti->type(objectid) == LWI_OBJECT)
|
|
{
|
|
_pmesh = _obi->meshInfo(objectid, 0);
|
|
if((_pmesh == NULL) && (childID == LWITEM_NULL))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!ExecCmd("SelectItem %x", objectid)) {
|
|
_msg->error("ERROR: Item selection\n", NULL);
|
|
return false;
|
|
}
|
|
for(int iServer=1;;iServer++) {
|
|
const char *strServer = _iti->server(objectid, "ItemMotionHandler", iServer);
|
|
if (strServer==NULL) {
|
|
break;
|
|
}
|
|
if (strcmp(strServer, DEBUGEXT "internal_SESectionAnimExport")==0) {
|
|
if (!ExecCmd("RemoveServer ItemMotionHandler %d", iServer)) {
|
|
_msg->error("ERROR: Applying ItemMotionHandler\n", NULL);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (childID != LWITEM_NULL) {
|
|
RemoveMotionHandler(childID);
|
|
childID = _iti->nextChild(objectid,childID);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ExportBones()
|
|
{
|
|
LWItemID idMasterObjID;
|
|
char strMessage[256];
|
|
|
|
if(!_evaluate)
|
|
{
|
|
// lightwave error
|
|
_msg->error("Lightwave process error !\nClose plugins window and try again.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
// !!!! make it work with a selected object, not the first one in scene
|
|
ReloadGlobalObjects();
|
|
|
|
bool bExportOnlySelected = false;
|
|
int ctSkeletonBones=0;
|
|
|
|
// find selected object - to be replaced with the master bone
|
|
int ctSelected = 0;
|
|
int ctMeshes=0;
|
|
_objid = _iti->first(LWI_OBJECT,0);
|
|
idMasterObjID = LWITEM_NULL;
|
|
while(_objid != LWITEM_NULL)
|
|
{
|
|
if(_iti->type(_objid) == LWI_OBJECT)
|
|
{
|
|
if(_ifi->itemFlags(_objid) & LWITEMF_SELECTED)
|
|
{
|
|
ctSelected++;
|
|
idMasterObjID = _objid;
|
|
}
|
|
ctMeshes++;
|
|
}
|
|
_objid = _iti->next(_objid);
|
|
}
|
|
|
|
if (idMasterObjID == LWITEM_NULL)
|
|
{
|
|
// lightwave error
|
|
_msg->error("ERROR: Object for top level bone not selected.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
if (ctSelected > 1)
|
|
{
|
|
// lightwave error
|
|
_msg->error("ERROR: More than one object selected.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
_ctNumBones = 0;
|
|
AddBoneToCount(idMasterObjID);
|
|
|
|
sprintf(strMessage,"Number of bones: %d",_ctNumBones);
|
|
|
|
|
|
// get scene name
|
|
_strFileName = strdup(_sci->filename);
|
|
|
|
// open the file to print into
|
|
char fnmOut[256];
|
|
strcpy(fnmOut, _strFileName);
|
|
char *pchDot = strrchr(fnmOut, '.');
|
|
if (pchDot!=NULL) {
|
|
strcpy(pchDot, ".as");
|
|
}
|
|
|
|
_msg->info(strMessage,fnmOut);
|
|
|
|
if ((_f = fopen(fnmOut,"w")) == NULL) {
|
|
_msg->error("ERROR: File open.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
fprintf(_f, "SE_SKELETON %s;\n\n",SE_ANIM_VER);
|
|
fprintf(_f, "BONES %d\n{\n",_ctNumBones);
|
|
|
|
_ctNumBones = 0;
|
|
WriteBoneInfo(idMasterObjID);
|
|
|
|
fprintf(_f, "}\n\nSE_SKELETON_END;\n");
|
|
fclose(_f);
|
|
|
|
|
|
return AFUNC_OK;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ExportSecAnim(LWXPanelID pan)
|
|
{
|
|
|
|
LWItemID idMasterObjID;
|
|
char strMessage[256];
|
|
Matrix12 bi_mRot;
|
|
|
|
|
|
_iFrame = 0;
|
|
_ctFrames = 0;
|
|
_ctBones = 0;
|
|
ctBoneEnvelopes = 0;
|
|
ctMorphEnvelopes = 0;
|
|
|
|
if(!_evaluate)
|
|
{
|
|
// lightwave error
|
|
_msg->error("Lightwave process error !\nClose plugins window and try again.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
// !!!! make it work with a selected object, not the first one in scene
|
|
ReloadGlobalObjects();
|
|
|
|
|
|
bool bExportOnlySelected = false;
|
|
int ctSkeletonBones=0;
|
|
|
|
// find selected object - to be replaced with the master bone
|
|
int ctSelected = 0;
|
|
int ctMeshes=0;
|
|
_objid = _iti->first(LWI_OBJECT,0);
|
|
idMasterObjID = LWITEM_NULL;
|
|
while(_objid != LWITEM_NULL)
|
|
{
|
|
if(_iti->type(_objid) == LWI_OBJECT)
|
|
{
|
|
if(_ifi->itemFlags(_objid) & LWITEMF_SELECTED)
|
|
{
|
|
ctSelected++;
|
|
idMasterObjID = _objid;
|
|
}
|
|
ctMeshes++;
|
|
}
|
|
_objid = _iti->next(_objid);
|
|
}
|
|
|
|
if (idMasterObjID == LWITEM_NULL)
|
|
{
|
|
// lightwave error
|
|
_msg->error("ERROR: Object for top level bone not selected.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
if (ctSelected > 1)
|
|
{
|
|
// lightwave error
|
|
_msg->error("ERROR: More than one object selected.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
// get scene name
|
|
_strFileName = strdup(_sci->filename);
|
|
|
|
// open the file to print into
|
|
char fnmOut[256];
|
|
strcpy(fnmOut, _strFileName);
|
|
char *pchDot = strrchr(fnmOut, '.');
|
|
if (pchDot!=NULL) {
|
|
strcpy(pchDot, ".aa");
|
|
}
|
|
_ctNumBones = 0;
|
|
AddBoneToCount(idMasterObjID);
|
|
|
|
|
|
if ((_f = fopen(fnmOut,"w")) == NULL) {
|
|
_msg->error("ERROR: File open.\n", NULL);
|
|
return AFUNC_BADAPP;
|
|
}
|
|
|
|
// calculate number of frames to export
|
|
_ctFrames = ((_ifi->previewEnd-_ifi->previewStart)/_ifi->previewStep)+1;
|
|
if (_ctFrames<=0) {
|
|
_ctFrames = 1;
|
|
}
|
|
|
|
|
|
// find all morph channels for the current mesh
|
|
_pmiFirst = NULL;
|
|
FindMorphChannels(NULL);
|
|
|
|
|
|
AddMotionHandler(idMasterObjID);
|
|
|
|
sprintf(strMessage,"ctBoneEnvelopes: %d",_ctBones);
|
|
_msg->error(strMessage,fnmOut);
|
|
|
|
|
|
bRecordDefaultFrame = true;
|
|
if (!ExecCmd("GoToFrame 0"))
|
|
{
|
|
// goto end;
|
|
}
|
|
bRecordDefaultFrame = false;
|
|
|
|
|
|
int bExportAnimBackward = *(int*)_xpanf->formGet( pan, ID_ANIM_ORDER);
|
|
|
|
float fTime;
|
|
// export normal order
|
|
if(!bExportAnimBackward) {
|
|
// for each frame in current preview selection
|
|
for (int iFrame=_ifi->previewStart; iFrame<=_ifi->previewEnd; iFrame+=_ifi->previewStep) {
|
|
// go to that frame
|
|
if (!ExecCmd("GoToFrame %d", iFrame)) {
|
|
// goto end;
|
|
}
|
|
|
|
assert(_iFrame>=0 && _iFrame<_ctFrames);
|
|
|
|
// NOTE: walking all frames implicitly lets the internal itemmotion handler record all bone positions
|
|
// we walk the morph maps manually
|
|
|
|
_iFrame++;
|
|
}
|
|
// get time
|
|
fTime = (float) GetCurrentTime();
|
|
// export backward
|
|
} else {
|
|
// remember time in last frame
|
|
if (!ExecCmd("GoToFrame %d", _ifi->previewEnd)) {
|
|
//goto end;
|
|
return AFUNC_BADGLOBAL;
|
|
}
|
|
// get time
|
|
fTime = (float) GetCurrentTime();
|
|
// for each frame in current preview selection going from last to first
|
|
for (int iFrame=_ifi->previewEnd; iFrame>=_ifi->previewStart; iFrame-=_ifi->previewStep) {
|
|
// go to that frame
|
|
if (!ExecCmd("GoToFrame %d", iFrame)) {
|
|
//goto end;
|
|
return AFUNC_BADGLOBAL;
|
|
}
|
|
|
|
assert(_iFrame>=0 && _iFrame<_ctFrames);
|
|
|
|
LWTimeInfo *_tmi = (LWTimeInfo *)_global( LWTIMEINFO_GLOBAL, GFUSE_TRANSIENT );
|
|
|
|
// NOTE: walking all frames implicitly lets the internal itemmotion handler record all bone positions
|
|
// we walk the morph maps manually
|
|
|
|
_iFrame++;
|
|
}
|
|
}
|
|
|
|
|
|
// find the number of morph envelopes
|
|
|
|
for(MorphInfo *ptmpmi=_pmiFirst;ptmpmi!=NULL; ptmpmi = ptmpmi->mi_pmiNext)
|
|
ctMorphEnvelopes++;
|
|
|
|
|
|
|
|
fTime = (float) GetCurrentTime();
|
|
char strAnimID[256];
|
|
strcpy(strAnimID,_strFileName);
|
|
GetAnimID(strAnimID);
|
|
|
|
fprintf(_f, "SE_ANIM %s;\n\n",SE_ANIM_VER);
|
|
fprintf(_f, "SEC_PER_FRAME %g;\n",fTime / _ifi->previewEnd * _ifi->previewStep);
|
|
fprintf(_f, "FRAMES %d;\n", _ctFrames);
|
|
fprintf(_f, "ANIM_ID \"%s\";\n\n", strAnimID);
|
|
|
|
|
|
fprintf(_f, "BONEENVELOPES %d\n{\n", _ctNumBones);
|
|
|
|
|
|
|
|
|
|
|
|
BoneInfo *pbiLast = NULL;
|
|
for (BoneInfo *pbi=_pbiFirst; pbi!=NULL; pbi = pbi->bi_pbiNext)
|
|
{
|
|
bool bRootBone = false;
|
|
|
|
// write its info
|
|
fprintf(_f, " NAME \"%s\"\n", pbi->bi_strName);
|
|
// write first frame - default pose
|
|
fprintf(_f, " DEFAULT_POSE {");
|
|
BoneFrame &bfDef = pbi->bi_abfFrames[0];
|
|
MakeRotationAndPosMatrix(bi_mRot,bfDef.fi_vPos,bfDef.fi_vRot);
|
|
PrintMatrix(_f,bi_mRot,0);
|
|
|
|
fprintf(_f, "}\n");
|
|
fprintf(_f, " {\n");
|
|
|
|
LWItemType itLast;
|
|
if(!pbiLast) itLast = LWI_OBJECT;
|
|
else itLast = pbiLast->bi_lwItemType;
|
|
|
|
|
|
// write anim
|
|
// for each frame
|
|
for (int iFrame=0; iFrame<_ctFrames; iFrame++)
|
|
{
|
|
// Fill 3x4 matrix and store rotation and position in it
|
|
BoneFrame &bf = pbi->bi_abfFrames[iFrame];
|
|
MakeRotationAndPosMatrix(bi_mRot,bf.fi_vPos,bf.fi_vRot);
|
|
|
|
// write matrix to file
|
|
PrintMatrix(_f,bi_mRot,4);
|
|
fprintf(_f,"\n");
|
|
|
|
}
|
|
pbiLast = pbi;
|
|
fprintf(_f," }\n\n");
|
|
}
|
|
|
|
fprintf(_f,"}\n");
|
|
|
|
fprintf(_f, "\nMORPHENVELOPES %d\n{\n", ctMorphEnvelopes);
|
|
|
|
// for each morph in list
|
|
{for (MorphInfo *pmi=_pmiFirst; pmi!=NULL; pmi = pmi->mi_pmiNext)
|
|
{
|
|
// write its info
|
|
fprintf(_f, " NAME \"%s\"\n", pmi->mi_strName);
|
|
fprintf(_f, " {\n");
|
|
for (int iFrame=0; iFrame<_ctFrames; iFrame++)
|
|
{
|
|
fprintf(_f, " %g;\n", pmi->mi_afFrames[iFrame]);
|
|
}
|
|
fprintf(_f," }\n\n");
|
|
}
|
|
}
|
|
|
|
fprintf(_f,"}\n");
|
|
|
|
// free all morph infos
|
|
{ MorphInfo *pmi=_pmiFirst;
|
|
MorphInfo *pmiNext=NULL;
|
|
for(;;) {
|
|
if(pmi==NULL) {
|
|
break;
|
|
}
|
|
pmiNext = pmi->mi_pmiNext;
|
|
|
|
free(pmi->mi_strName);
|
|
free(pmi->mi_afFrames);
|
|
free(pmi);
|
|
|
|
pmi = pmiNext;
|
|
}}
|
|
|
|
|
|
|
|
fprintf(_f, "SE_ANIM_END;\n");
|
|
fclose(_f);
|
|
|
|
RemoveMotionHandler(idMasterObjID);
|
|
_pbiFirst = NULL;
|
|
|
|
return AFUNC_OK;
|
|
|
|
};
|