Serious-Engine/Sources/LWSkaExporter/ModelerMeshExporter.cpp

712 lines
22 KiB
C++
Raw Permalink Normal View History

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;
if (_meshEditOperations == NULL) {
2016-03-23 18:42:20 +01:00
_msg->error("Error!", "Error _meshEditOperations is NULL!");
2016-03-11 14:57:17 +01:00
return;
}
2016-03-23 18:42:20 +01:00
_state = _meshEditOperations->state;
2016-03-11 14:57:17 +01:00
_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!");
2016-03-23 18:42:20 +01:00
return;
2016-03-11 14:57:17 +01:00
}
// 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;
}
}