Serious-Engine/Sources/LWSkaExporter/SectionsExport.cpp
2016-03-11 18:20:51 -06:00

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;
};