2016-03-12 01:20:51 +01:00
|
|
|
/* 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. */
|
2016-03-11 14:57:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "base.h"
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
FILE *_fpOutput = NULL;
|
|
|
|
|
|
|
|
EDStateRef _state;
|
|
|
|
|
|
|
|
extern int msgbox_modeler( LWXPanelFuncs *xpanf, const char* msg );
|
|
|
|
|
|
|
|
|
|
|
|
extern LWItemID _objid;
|
|
|
|
LWSurfaceID *_asurSurfaces;
|
|
|
|
extern char *_strFileName;
|
|
|
|
|
|
|
|
// arrays of all point and polygon ids
|
|
|
|
extern int _ctPntIDs;
|
|
|
|
extern int _iPnt;
|
|
|
|
extern LWPntID *_aidPntIDs;
|
|
|
|
|
|
|
|
extern int _ctPolIDs;
|
|
|
|
extern int _iPol;
|
|
|
|
extern LWPolID *_aidPolIDs;
|
|
|
|
|
|
|
|
// point coordinates
|
|
|
|
extern float (*_avPnts)[3];
|
|
|
|
// polygon normals
|
|
|
|
extern float (*_avPolNormals)[3];
|
|
|
|
// point normals
|
|
|
|
extern float (*_avPntNormals)[3];
|
|
|
|
|
|
|
|
// uvmapnames
|
|
|
|
extern const char **_astrUVMapNames;
|
|
|
|
extern int _ctUVMapNames;
|
|
|
|
extern int _ctUsedUVMapNames;
|
|
|
|
// weightmapnames
|
|
|
|
extern const char **_astrWeightMapNames;
|
|
|
|
extern int *_actWeightMapCounts;
|
|
|
|
extern int _ctWeightMapNames;
|
|
|
|
extern int _ctUsedWeightMapNames;
|
|
|
|
|
|
|
|
// relmorphmapnames
|
|
|
|
extern const char **_astrRelMorphMapNames;
|
|
|
|
extern int *_actRelMorphMapCounts;
|
|
|
|
extern int _ctRelMorphMapNames;
|
|
|
|
extern int _ctUsedRelMorphMapNames;
|
|
|
|
|
|
|
|
// absmorphmapnames
|
|
|
|
extern const char **_astrAbsMorphMapNames;
|
|
|
|
extern int *_actAbsMorphMapCounts;
|
|
|
|
extern int _ctAbsMorphMapNames;
|
|
|
|
extern int _ctUsedAbsMorphMapNames;
|
|
|
|
|
|
|
|
// here we store ids for all point and polygon combinations in order by polygons and by points, effectively
|
|
|
|
// having all info needed to handle the unwelded object and info needed to calculate normals
|
|
|
|
extern int _ctPolPnts;
|
|
|
|
extern PolPnt *_appPolPnts;
|
|
|
|
extern PolPnt *_appPntPols;
|
|
|
|
|
|
|
|
extern int _ctSurfs;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int EnumPnts_modeler(void *, const EDPointInfo *poiPointInfo)
|
|
|
|
{
|
|
|
|
_aidPntIDs[_iPnt++] = poiPointInfo->pnt;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int EnumPols_modeler(void *, const EDPolygonInfo *pliPollyInfo)
|
|
|
|
{
|
|
|
|
|
|
|
|
_aidPolIDs[_iPol++] = pliPollyInfo->pol;
|
|
|
|
|
|
|
|
if (pliPollyInfo->numPnts != 3) {
|
|
|
|
_msg->error("All objects must be triangles!", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
_ctPolPnts += pliPollyInfo->numPnts;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int __cdecl qsort_CompareIDs_modeler(const void *elem1, const void *elem2)
|
|
|
|
{
|
|
|
|
return *(int*)elem1-*(int*)elem2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int __cdecl qsort_ComparePolPntsByPnt_modeler(const void *elem1, const void *elem2)
|
|
|
|
{
|
|
|
|
PolPnt *pp1 = (struct PolPnt *)elem1;
|
|
|
|
PolPnt *pp2 = (struct PolPnt *)elem2;
|
|
|
|
|
|
|
|
return (int)pp1->pp_idPnt-(int)pp2->pp_idPnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fill base vertex coordinates (without morphing)
|
|
|
|
void FillOriginalVertexCoords_modeler(void)
|
|
|
|
{
|
|
|
|
EDPointInfo * poiPoint;
|
|
|
|
|
|
|
|
// for each vertex
|
|
|
|
for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
|
|
|
|
// get the coords
|
|
|
|
poiPoint = _meshEditOperations->pointInfo(_state, _aidPntIDs[iPnt]);
|
|
|
|
_avPnts[iPnt][0] = (float) poiPoint->position[0];
|
|
|
|
_avPnts[iPnt][1] = (float) poiPoint->position[1];
|
|
|
|
_avPnts[iPnt][2] = (float) poiPoint->position[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// fill vertex coordinates with relative morphing
|
|
|
|
void FillRelativeMorphVertexCoords_modeler(const char *strRelMorphMapName)
|
|
|
|
{
|
|
|
|
// fill base vertex coordinates (without morphing)
|
|
|
|
FillOriginalVertexCoords_modeler();
|
|
|
|
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_MORF, strRelMorphMapName);
|
|
|
|
|
|
|
|
// for each vertex
|
|
|
|
{for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
|
|
|
|
// if morphed
|
|
|
|
float v[3];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _aidPntIDs[iPnt], v)) {
|
|
|
|
// apply the morph
|
|
|
|
_avPnts[iPnt][0]+=v[0];
|
|
|
|
_avPnts[iPnt][1]+=v[1];
|
|
|
|
_avPnts[iPnt][2]+=v[2];
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
// fill vertex coordinates with absolute morphing
|
|
|
|
void FillAbsoluteMorphVertexCoords_modeler(const char *strAbsMorphMapName)
|
|
|
|
{
|
|
|
|
// fill base vertex coordinates (without morphing)
|
|
|
|
FillOriginalVertexCoords_modeler();
|
|
|
|
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_SPOT, strAbsMorphMapName);
|
|
|
|
|
|
|
|
// for each vertex
|
|
|
|
{for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
|
|
|
|
// if morphed
|
|
|
|
float v[3];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _aidPntIDs[iPnt], v)) {
|
|
|
|
// apply the morph
|
|
|
|
_avPnts[iPnt][0] = v[0];
|
|
|
|
_avPnts[iPnt][1] = v[1];
|
|
|
|
_avPnts[iPnt][2] = v[2];
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GetPntIndex_modeler(LWPntID id)
|
|
|
|
{
|
|
|
|
LWPntID *p = (LWPntID *)bsearch(&id, _aidPntIDs, _ctPntIDs, sizeof(id), qsort_CompareIDs_modeler);
|
|
|
|
if (p==NULL) {
|
|
|
|
assert(false);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return p-_aidPntIDs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int GetPolIndex_modeler(LWPolID id)
|
|
|
|
{
|
|
|
|
LWPolID *p = (LWPolID *)bsearch(&id, _aidPolIDs, _ctPolIDs, sizeof(id), qsort_CompareIDs_modeler);
|
|
|
|
if (p==NULL) {
|
|
|
|
assert(false);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return p-_aidPolIDs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MakeNormals_modeler(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// generate polygon normals
|
|
|
|
for(int iPol=0; iPol<_ctPolIDs; iPol++) {
|
|
|
|
LWPolID idPol = _aidPolIDs[iPol];
|
|
|
|
double dPolNormal[3];
|
|
|
|
_meshEditOperations->polyNormal(_state,idPol,dPolNormal);
|
|
|
|
|
|
|
|
_avPolNormals[iPol][0] = (float) dPolNormal[0];
|
|
|
|
_avPolNormals[iPol][1] = (float) dPolNormal[1];
|
|
|
|
_avPolNormals[iPol][2] = (float) dPolNormal[2];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate point normals
|
|
|
|
memset(_avPntNormals, 0, _ctPntIDs*sizeof(float)*3);
|
|
|
|
|
|
|
|
float vNormalSum[3];
|
|
|
|
LWPntID idLastPnt = NULL;
|
|
|
|
|
|
|
|
// for each point polygon
|
|
|
|
{for(int iPntPol=0; iPntPol<_ctPolPnts; iPntPol++) {
|
|
|
|
LWPntID idThis = _appPntPols[iPntPol].pp_idPnt;
|
|
|
|
// if new point
|
|
|
|
if (idThis!=idLastPnt) {
|
|
|
|
// store value for the last point (unless it was the first one)
|
|
|
|
if (idLastPnt!=NULL) {
|
|
|
|
int iLastPnt = GetPntIndex_modeler(idLastPnt);
|
|
|
|
normalize(vNormalSum);
|
|
|
|
_avPntNormals[iLastPnt][0] = vNormalSum[0];
|
|
|
|
_avPntNormals[iLastPnt][1] = vNormalSum[1];
|
|
|
|
_avPntNormals[iLastPnt][2] = vNormalSum[2];
|
|
|
|
}
|
|
|
|
// reset averaging values
|
|
|
|
vNormalSum[0] = 0.0f;
|
|
|
|
vNormalSum[1] = 0.0f;
|
|
|
|
vNormalSum[2] = 0.0f;
|
|
|
|
}
|
|
|
|
// add the polygon normal to the averaging values
|
|
|
|
int iPol = GetPolIndex_modeler(_appPntPols[iPntPol].pp_idPol);
|
|
|
|
vNormalSum[0] += _avPolNormals[iPol][0];
|
|
|
|
vNormalSum[1] += _avPolNormals[iPol][1];
|
|
|
|
vNormalSum[2] += _avPolNormals[iPol][2];
|
|
|
|
|
|
|
|
idLastPnt=idThis;
|
|
|
|
}}
|
|
|
|
|
|
|
|
int iLastPnt = GetPntIndex_modeler(idLastPnt);
|
|
|
|
normalize(vNormalSum);
|
|
|
|
_avPntNormals[iLastPnt][0] = vNormalSum[0];
|
|
|
|
_avPntNormals[iLastPnt][1] = vNormalSum[1];
|
|
|
|
_avPntNormals[iLastPnt][2] = vNormalSum[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// extract polygon and point info
|
|
|
|
void ExtractMeshData_modeler(void)
|
|
|
|
{
|
|
|
|
// extract point and poly ids, so we can walk them later
|
|
|
|
_aidPntIDs = (LWPntID*)malloc(_ctPntIDs*sizeof(LWPntID));
|
|
|
|
_iPnt = 0;
|
|
|
|
_meshEditOperations->pointScan(_state,EnumPnts_modeler,NULL,OPLYR_FG);
|
|
|
|
qsort(_aidPntIDs, _ctPntIDs, sizeof(LWPntID), qsort_CompareIDs_modeler);
|
|
|
|
|
|
|
|
_aidPolIDs = (LWPolID*)malloc(_ctPolIDs*sizeof(LWPolID));
|
|
|
|
_iPol = 0;
|
|
|
|
_ctPolPnts = 0;
|
|
|
|
_meshEditOperations->polyScan(_state,EnumPols_modeler,NULL,OPLYR_FG);
|
|
|
|
qsort(_aidPolIDs, _ctPolIDs, sizeof(LWPolID), qsort_CompareIDs_modeler);
|
|
|
|
|
|
|
|
_appPolPnts = (PolPnt *)malloc(_ctPolPnts*sizeof(PolPnt));
|
|
|
|
_appPntPols = (PolPnt *)malloc(_ctPolPnts*sizeof(PolPnt));
|
|
|
|
// fill in all point and polygon combinations
|
|
|
|
{int iPolPnt = 0;
|
|
|
|
EDPolygonInfo *pliPolly;
|
|
|
|
for(int iPol=0; iPol<_ctPolIDs; iPol++) {
|
|
|
|
LWPolID idPol = _aidPolIDs[iPol];
|
|
|
|
pliPolly = _meshEditOperations->polyInfo(_state,idPol);
|
|
|
|
int ctInThisPol = pliPolly->numPnts;
|
|
|
|
for (int iPnt=0; iPnt<ctInThisPol; iPnt++) {
|
|
|
|
_appPolPnts[iPolPnt].pp_idPol = idPol;
|
|
|
|
_appPolPnts[iPolPnt].pp_idPnt = pliPolly->points[iPnt];
|
|
|
|
iPolPnt++;
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
// copy to per-point array and sort by points
|
|
|
|
memcpy(_appPntPols, _appPolPnts, _ctPolPnts*sizeof(PolPnt));
|
|
|
|
qsort(_appPntPols, _ctPolPnts, sizeof(PolPnt), qsort_ComparePolPntsByPnt_modeler);
|
|
|
|
|
|
|
|
|
|
|
|
// allocate point coords and polygon and point normals
|
|
|
|
_avPnts = (float(*)[3])malloc(_ctPntIDs*sizeof(float)*3);
|
|
|
|
_avPolNormals = (float(*)[3])malloc(_ctPolIDs*sizeof(float)*3);
|
|
|
|
_avPntNormals = (float(*)[3])malloc(_ctPntIDs*sizeof(float)*3);
|
|
|
|
|
|
|
|
// calculate mesh normals using base vertex coordinates (without morphing)
|
|
|
|
FillOriginalVertexCoords_modeler();
|
|
|
|
MakeNormals_modeler();
|
|
|
|
|
|
|
|
|
|
|
|
// list all the uvmaps used by this object
|
|
|
|
_ctUVMapNames = _objfunc->numVMaps(LWVMAP_TXUV);
|
|
|
|
_astrUVMapNames = (const char**) malloc(_ctUVMapNames*sizeof(char*));
|
|
|
|
memset(_astrUVMapNames, 0, _ctUVMapNames*sizeof(char*));
|
|
|
|
_ctUsedUVMapNames = 0;
|
|
|
|
{for(int iUVMap=0; iUVMap<_ctUVMapNames; iUVMap++) {
|
|
|
|
const char *strName = _objfunc->vmapName(LWVMAP_TXUV, iUVMap);
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_TXUV, strName);
|
|
|
|
bool bExists = false;
|
|
|
|
for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
|
|
|
|
float v[2];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _aidPntIDs[iPnt], v)) {
|
|
|
|
bExists = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bExists) {
|
|
|
|
_astrUVMapNames[_ctUsedUVMapNames++] = strName;
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
|
|
// list all the weightmaps used by this object
|
|
|
|
_ctWeightMapNames = _objfunc->numVMaps(LWVMAP_WGHT);
|
|
|
|
_astrWeightMapNames = (const char**) malloc(_ctWeightMapNames*sizeof(char*));
|
|
|
|
_actWeightMapCounts = (int *) malloc(_ctWeightMapNames*sizeof(int));
|
|
|
|
memset(_astrWeightMapNames, 0, _ctWeightMapNames*sizeof(char*));
|
|
|
|
memset(_actWeightMapCounts, 0, _ctWeightMapNames*sizeof(int));
|
|
|
|
_ctUsedWeightMapNames = 0;
|
|
|
|
{for(int iWeightMap=0; iWeightMap<_ctWeightMapNames; iWeightMap++) {
|
|
|
|
const char *strName = _objfunc->vmapName(LWVMAP_WGHT, iWeightMap);
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_WGHT, strName);
|
|
|
|
int ct = 0;
|
|
|
|
// for each polygonvertex
|
|
|
|
for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// get the weight
|
|
|
|
float v[1];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _appPolPnts[iPolPnt].pp_idPnt, v) && v[0]!=0.0f) {
|
|
|
|
ct++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ct>0)
|
|
|
|
{
|
|
|
|
_astrWeightMapNames[_ctUsedWeightMapNames] = strName;
|
|
|
|
_actWeightMapCounts[_ctUsedWeightMapNames] = ct;
|
|
|
|
_ctUsedWeightMapNames++;
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// list all the relmorphmaps used by this object
|
|
|
|
_ctRelMorphMapNames = _objfunc->numVMaps(LWVMAP_MORF);
|
|
|
|
_astrRelMorphMapNames = (const char**) malloc(_ctRelMorphMapNames*sizeof(char*));
|
|
|
|
_actRelMorphMapCounts = (int *) malloc(_ctRelMorphMapNames*sizeof(int));
|
|
|
|
memset(_astrRelMorphMapNames, 0, _ctRelMorphMapNames*sizeof(char*));
|
|
|
|
memset(_actRelMorphMapCounts, 0, _ctRelMorphMapNames*sizeof(int));
|
|
|
|
_ctUsedRelMorphMapNames = 0;
|
|
|
|
{for(int iRelMorphMap=0; iRelMorphMap<_ctRelMorphMapNames; iRelMorphMap++) {
|
|
|
|
const char *strName = _objfunc->vmapName(LWVMAP_MORF, iRelMorphMap);
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_MORF, strName);
|
|
|
|
int ct = 0;
|
|
|
|
// for each polygonvertex
|
|
|
|
for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// get the morphpos
|
|
|
|
float v[3];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _appPolPnts[iPolPnt].pp_idPnt, v)) {
|
|
|
|
ct++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ct>0) {
|
|
|
|
_astrRelMorphMapNames[_ctUsedRelMorphMapNames] = strName;
|
|
|
|
}
|
|
|
|
_actRelMorphMapCounts[_ctUsedRelMorphMapNames] = ct;
|
|
|
|
_ctUsedRelMorphMapNames++;
|
|
|
|
}}
|
|
|
|
|
|
|
|
// list all the absmorphmaps used by this object
|
|
|
|
_ctAbsMorphMapNames = _objfunc->numVMaps(LWVMAP_SPOT);
|
|
|
|
_astrAbsMorphMapNames = (const char**) malloc(_ctAbsMorphMapNames*sizeof(char*));
|
|
|
|
_actAbsMorphMapCounts = (int *) malloc(_ctAbsMorphMapNames*sizeof(int));
|
|
|
|
memset(_astrAbsMorphMapNames, 0, _ctAbsMorphMapNames*sizeof(char*));
|
|
|
|
memset(_actAbsMorphMapCounts, 0, _ctAbsMorphMapNames*sizeof(int));
|
|
|
|
_ctUsedAbsMorphMapNames = 0;
|
|
|
|
{for(int iAbsMorphMap=0; iAbsMorphMap<_ctAbsMorphMapNames; iAbsMorphMap++) {
|
|
|
|
const char *strName = _objfunc->vmapName(LWVMAP_SPOT, iAbsMorphMap);
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_SPOT, strName);
|
|
|
|
int ct = 0;
|
|
|
|
// for each polygonvertex
|
|
|
|
for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// get the morphpos
|
|
|
|
float v[3];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _appPolPnts[iPolPnt].pp_idPnt, v)) {
|
|
|
|
ct++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ct>0) {
|
|
|
|
_astrAbsMorphMapNames[_ctUsedAbsMorphMapNames] = strName;
|
|
|
|
}
|
|
|
|
_actAbsMorphMapCounts[_ctUsedAbsMorphMapNames] = ct;
|
|
|
|
_ctUsedAbsMorphMapNames++;
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ExportMesh_modeler(int iFaceForward) {
|
|
|
|
char fnmOut[256];
|
|
|
|
char *strFileName;
|
|
|
|
|
|
|
|
_state = _meshEditOperations->state;
|
|
|
|
|
|
|
|
if (_meshEditOperations == NULL) {
|
|
|
|
_msg->error("Error!","Error _meshEditOperations is NULL!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_ctPntIDs = _meshEditOperations->pointCount(_state,OPLYR_FG,EDCOUNT_ALL);
|
|
|
|
_ctPolIDs = _meshEditOperations->polyCount(_state,OPLYR_FG,EDCOUNT_ALL);
|
|
|
|
|
|
|
|
strFileName = strdup(_statequery->object());
|
|
|
|
|
|
|
|
strcpy(fnmOut, strFileName);
|
|
|
|
char *pchDot = strrchr(fnmOut, '.');
|
|
|
|
if (pchDot!=NULL) {
|
|
|
|
strcpy(pchDot, ".am");
|
|
|
|
}
|
|
|
|
|
|
|
|
//msgbox(_xpanf,fnmOut);
|
|
|
|
|
|
|
|
ExtractMeshData_modeler();
|
|
|
|
|
|
|
|
_fpOutput = fopen(fnmOut, "w");
|
|
|
|
if (_fpOutput==NULL) {
|
|
|
|
msgbox_modeler(_xpanf, "Can't open file!");
|
|
|
|
}
|
|
|
|
|
|
|
|
// write the mesh header
|
|
|
|
fprintf(_fpOutput, "SE_MESH %s;\n\n",SE_ANIM_VER);
|
|
|
|
// is mesh face forward
|
|
|
|
|
|
|
|
if(iFaceForward==ML_HALF_FACE_FORWARD) {
|
|
|
|
fprintf(_fpOutput, "HALF_FACE_FORWARD TRUE;\n\n");
|
|
|
|
} else if(iFaceForward==ML_FULL_FACE_FORWARD) {
|
|
|
|
fprintf(_fpOutput, "FULL_FACE_FORWARD TRUE;\n\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// write the vertex header
|
|
|
|
fprintf(_fpOutput, "VERTICES %d\n", _ctPolPnts);
|
|
|
|
fprintf(_fpOutput, "{\n");
|
|
|
|
// for each polygonvertex
|
|
|
|
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// get the coords
|
|
|
|
EDPointInfo * poiPoint;
|
|
|
|
double v[3];
|
|
|
|
poiPoint = _meshEditOperations->pointInfo(_state, _appPolPnts[iPolPnt].pp_idPnt);
|
|
|
|
v[0] = (float) poiPoint->position[0];
|
|
|
|
v[1] = (float) poiPoint->position[1];
|
|
|
|
v[2] = (float) poiPoint->position[2];
|
|
|
|
|
|
|
|
fprintf(_fpOutput, " %g, %g, %g;\n", v[0], v[1], -v[2]);
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, "}\n\n");
|
|
|
|
|
|
|
|
// write the normal header
|
|
|
|
fprintf(_fpOutput, "NORMALS %d\n", _ctPolPnts);
|
|
|
|
fprintf(_fpOutput, "{\n");
|
|
|
|
// for each polygonvertex
|
|
|
|
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// get the normal
|
|
|
|
int iPnt = GetPntIndex_modeler(_appPolPnts[iPolPnt].pp_idPnt);
|
|
|
|
fprintf(_fpOutput, " %g, %g, %g;\n", _avPntNormals[iPnt][0], _avPntNormals[iPnt][1], -_avPntNormals[iPnt][2]);
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, "}\n\n");
|
|
|
|
|
|
|
|
|
|
|
|
// write the uvmaps header
|
|
|
|
fprintf(_fpOutput, "UVMAPS %d\n", _ctUsedUVMapNames);
|
|
|
|
fprintf(_fpOutput, "{\n");
|
|
|
|
|
|
|
|
if (_ctUsedUVMapNames == 0) {
|
|
|
|
_msg->info("No UV maps in the scene!",NULL);
|
|
|
|
}
|
|
|
|
// for each uvmap
|
|
|
|
{for(int iUVMap=0; iUVMap<_ctUsedUVMapNames; iUVMap++) {
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
const char *strUVMap = _astrUVMapNames[iUVMap];
|
|
|
|
fprintf(_fpOutput, " NAME \"%s\";\n", strUVMap);
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_TXUV, strUVMap);
|
|
|
|
fprintf(_fpOutput, " TEXCOORDS %d\n", _ctPolPnts);
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
|
|
|
|
// for each polygonvertex
|
|
|
|
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// get the coords
|
|
|
|
float v[2];
|
|
|
|
if (_meshEditOperations->pointVPGet(_state, _appPolPnts[iPolPnt].pp_idPnt, _appPolPnts[iPolPnt].pp_idPol, v)) {
|
|
|
|
} else if (_meshEditOperations->pointVGet(_state, _appPolPnts[iPolPnt].pp_idPnt, v)) {
|
|
|
|
} else {
|
|
|
|
v[0] = 0.0f;
|
|
|
|
v[1] = 0.0f;
|
|
|
|
}
|
|
|
|
fprintf(_fpOutput, " %g, %g;\n", v[0], 1.0f-v[1]);
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, "}\n\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get surfaces
|
|
|
|
_asurSurfaces = _srf->byObject(strFileName);
|
|
|
|
|
|
|
|
// count the surfaces
|
|
|
|
_ctSurfs = 0;
|
|
|
|
while(_asurSurfaces[_ctSurfs]!=NULL) {
|
|
|
|
_ctSurfs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write the surfaces header
|
|
|
|
fprintf(_fpOutput, "SURFACES %d\n", _ctSurfs);
|
|
|
|
fprintf(_fpOutput, "{\n");
|
|
|
|
// for each surface
|
|
|
|
{for(int iSurf=0; iSurf<_ctSurfs; iSurf++) {
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
const char *strSurf = _srf->name(_asurSurfaces[iSurf]);
|
|
|
|
fprintf(_fpOutput, " NAME \"%s\";\n", strSurf);
|
|
|
|
// count the polygons
|
|
|
|
int iSurfPols = 0;
|
|
|
|
{for(int i=0; i<_ctPolIDs; i++) {
|
|
|
|
if (strcmp(_meshEditOperations->polyTag(_state, _aidPolIDs[i], LWPTAG_SURF), strSurf)==0) {
|
|
|
|
iSurfPols++;
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
// write the polygon set header
|
|
|
|
fprintf(_fpOutput, " TRIANGLE_SET %d\n", iSurfPols);
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
// for each polygon
|
|
|
|
for(int iTri=0; iTri<_ctPolIDs; iTri++) {
|
|
|
|
LWPolID idPol = _aidPolIDs[iTri];
|
|
|
|
// if not in this surface
|
|
|
|
if (strcmp(_meshEditOperations->polyTag(_state, idPol, LWPTAG_SURF), strSurf)!=0) {
|
|
|
|
// skip it
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
fprintf(_fpOutput, " %d, %d, %d;\n", iTri*3+2, iTri*3+1, iTri*3+0);
|
|
|
|
}
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, "}\n");
|
|
|
|
|
|
|
|
// write the weightmaps header
|
|
|
|
fprintf(_fpOutput, "WEIGHTS %d\n", _ctUsedWeightMapNames);
|
|
|
|
fprintf(_fpOutput, "{\n");
|
|
|
|
|
|
|
|
// for each weightmap
|
|
|
|
{for(int iWeightMap=0; iWeightMap<_ctUsedWeightMapNames; iWeightMap++) {
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
const char *strWeightMap = _astrWeightMapNames[iWeightMap];
|
|
|
|
fprintf(_fpOutput, " NAME \"%s\";\n", strWeightMap);
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_WGHT, strWeightMap);
|
|
|
|
fprintf(_fpOutput, " WEIGHT_SET %d\n", _actWeightMapCounts[iWeightMap]);
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
|
|
|
|
// for each polygonvertex
|
|
|
|
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// get the coords
|
|
|
|
float v[1];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _appPolPnts[iPolPnt].pp_idPnt, v) && v[0]!=0.0f) {
|
|
|
|
if (v[0] < 0) {
|
|
|
|
_msg->error("Weight map value lesser than zero!",NULL);
|
|
|
|
} else {
|
|
|
|
fprintf(_fpOutput, " { %d; %g; }\n", iPolPnt, v[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, "}\n\n");
|
|
|
|
|
|
|
|
|
|
|
|
// write the morphmaps header
|
|
|
|
fprintf(_fpOutput, "MORPHS %d\n", _ctUsedRelMorphMapNames+_ctUsedAbsMorphMapNames);
|
|
|
|
fprintf(_fpOutput, "{\n");
|
|
|
|
|
|
|
|
|
|
|
|
// for each relmorphmap
|
|
|
|
{for(int iRelMorphMap=0; iRelMorphMap<_ctUsedRelMorphMapNames; iRelMorphMap++) {
|
|
|
|
const char *strRelMorphMap = _astrRelMorphMapNames[iRelMorphMap];
|
|
|
|
// calculate mesh normals using the given morphmap
|
|
|
|
FillRelativeMorphVertexCoords_modeler(strRelMorphMap);
|
|
|
|
MakeNormals_modeler();
|
|
|
|
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
fprintf(_fpOutput, " NAME \"%s\";\n", strRelMorphMap);
|
|
|
|
fprintf(_fpOutput, " RELATIVE TRUE;\n");
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_MORF, strRelMorphMap);
|
|
|
|
fprintf(_fpOutput, " MORPH_SET %d\n", _actRelMorphMapCounts[iRelMorphMap]);
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
|
|
|
|
// for each polygonvertex
|
|
|
|
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// if morphed here
|
|
|
|
float vRel[3];
|
|
|
|
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _appPolPnts[iPolPnt].pp_idPnt, vRel)) {
|
|
|
|
// write the coords and normal
|
|
|
|
int iPnt = GetPntIndex_modeler(_appPolPnts[iPolPnt].pp_idPnt);
|
|
|
|
fprintf(_fpOutput, " { %d; %g, %g, %g; %g, %g, %g; }\n", iPolPnt,
|
|
|
|
_avPnts[iPnt][0], _avPnts[iPnt][1], -_avPnts[iPnt][2],
|
|
|
|
_avPntNormals[iPnt][0], _avPntNormals[iPnt][1], -_avPntNormals[iPnt][2]);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
}}
|
|
|
|
// for each absmorphmap
|
|
|
|
{for(int iAbsMorphMap=0; iAbsMorphMap<_ctUsedAbsMorphMapNames; iAbsMorphMap++) {
|
|
|
|
const char *strAbsMorphMap = _astrAbsMorphMapNames[iAbsMorphMap];
|
|
|
|
// calculate mesh normals using the given morphmap
|
|
|
|
FillAbsoluteMorphVertexCoords_modeler(strAbsMorphMap);
|
|
|
|
MakeNormals_modeler();
|
|
|
|
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
fprintf(_fpOutput, " NAME \"%s\";\n", strAbsMorphMap);
|
|
|
|
fprintf(_fpOutput, " RELATIVE FALSE;\n");
|
|
|
|
void *pMap = _meshEditOperations->pointVSet(_state,NULL, LWVMAP_MORF, strAbsMorphMap);
|
|
|
|
fprintf(_fpOutput, " MORPH_SET %d\n", _actAbsMorphMapCounts[iAbsMorphMap]);
|
|
|
|
fprintf(_fpOutput, " {\n");
|
|
|
|
|
|
|
|
// for each polygonvertex
|
|
|
|
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
|
|
|
|
// if morphed here
|
|
|
|
float vRel[3];
|
|
|
|
if (_meshEditOperations->pointVGet(_state, _appPolPnts[iPolPnt].pp_idPnt, vRel)) {
|
|
|
|
// write the coords and normal
|
|
|
|
int iPnt = GetPntIndex_modeler(_appPolPnts[iPolPnt].pp_idPnt);
|
|
|
|
fprintf(_fpOutput, " { %d; %g, %g, %g; %g, %g, %g; }\n", iPolPnt,
|
|
|
|
_avPnts[iPnt][0], _avPnts[iPnt][1], -_avPnts[iPnt][2],
|
|
|
|
_avPntNormals[iPnt][0], _avPntNormals[iPnt][1], -_avPntNormals[iPnt][2]);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
fprintf(_fpOutput, " }\n");
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
|
|
fprintf(_fpOutput, "}\n\n");
|
|
|
|
fprintf(_fpOutput, "SE_MESH_END;\n");
|
|
|
|
|
|
|
|
_msg->info("Saved:", fnmOut);
|
|
|
|
|
|
|
|
// close and free everything
|
|
|
|
if (_fpOutput!=NULL) {
|
|
|
|
fclose(_fpOutput);
|
|
|
|
_fpOutput=NULL;
|
|
|
|
}
|
|
|
|
if (_aidPntIDs!=NULL) {
|
|
|
|
free(_aidPntIDs);
|
|
|
|
_aidPntIDs = NULL;
|
|
|
|
}
|
|
|
|
if (_aidPolIDs!=NULL) {
|
|
|
|
free(_aidPolIDs);
|
|
|
|
_aidPolIDs = NULL;
|
|
|
|
}
|
|
|
|
if (_appPolPnts!=NULL) {
|
|
|
|
free(_appPolPnts);
|
|
|
|
_appPolPnts = NULL;
|
|
|
|
}
|
|
|
|
if (_appPntPols!=NULL) {
|
|
|
|
free(_appPntPols);
|
|
|
|
_appPntPols = NULL;
|
|
|
|
}
|
|
|
|
if (_avPnts!=NULL) {
|
|
|
|
free(_avPnts);
|
|
|
|
_avPnts = NULL;
|
|
|
|
}
|
|
|
|
if (_avPolNormals!=NULL) {
|
|
|
|
free(_avPolNormals);
|
|
|
|
_avPolNormals = NULL;
|
|
|
|
}
|
|
|
|
if (_avPntNormals!=NULL) {
|
|
|
|
free(_avPntNormals);
|
|
|
|
_avPntNormals = NULL;
|
|
|
|
}
|
|
|
|
if (strFileName!=NULL) {
|
|
|
|
free(strFileName);
|
|
|
|
strFileName = NULL;
|
|
|
|
}
|
|
|
|
if (_astrUVMapNames!=NULL) {
|
|
|
|
free(_astrUVMapNames);
|
|
|
|
_astrUVMapNames = NULL;
|
|
|
|
}
|
|
|
|
if (_astrWeightMapNames!=NULL) {
|
|
|
|
free(_astrWeightMapNames);
|
|
|
|
_astrWeightMapNames = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|