Serious-Engine/Sources/LWSkaExporter/MeshExport.cpp
2016-03-11 15:57:17 +02:00

747 lines
23 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
#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 "vecmat.h"
#include "base.h"
static LWItemID _objid = NULL;
static LWSurfaceID *_asurSurfaces = NULL;
static char *_strFileName = NULL;
// arrays of all point and polygon ids
int _ctPntIDs = 0;
int _iPnt = 0;
LWPntID *_aidPntIDs = NULL;
int _ctPolIDs = 0;
int _iPol = 0;
LWPolID *_aidPolIDs = NULL;
// point coordinates
float (*_avPnts)[3] = NULL;
// polygon normals
float (*_avPolNormals)[3] = NULL;
// point normals
float (*_avPntNormals)[3] = NULL;
// uvmapnames
const char **_astrUVMapNames = NULL;
int _ctUVMapNames = 0;
int _ctUsedUVMapNames = 0;
// weightmapnames
const char **_astrWeightMapNames = NULL;
int *_actWeightMapCounts = NULL;
int _ctWeightMapNames = 0;
int _ctUsedWeightMapNames = 0;
// relmorphmapnames
const char **_astrRelMorphMapNames = NULL;
int *_actRelMorphMapCounts = NULL;
int _ctRelMorphMapNames = 0;
int _ctUsedRelMorphMapNames = 0;
// absmorphmapnames
const char **_astrAbsMorphMapNames = NULL;
int *_actAbsMorphMapCounts = NULL;
int _ctAbsMorphMapNames = 0;
int _ctUsedAbsMorphMapNames = 0;
// 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
int _ctPolPnts = 0;
PolPnt *_appPolPnts = NULL;
PolPnt *_appPntPols = NULL;
int _ctSurfs = 0;
extern int ReloadGlobalObjects();
// helper functions for ID sorting/searching
int __cdecl qsort_CompareIDs(const void *elem1, const void *elem2)
{
return *(int*)elem1-*(int*)elem2;
}
int __cdecl qsort_ComparePolPntsByPnt(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;
}
int GetPntIndex(LWPntID id)
{
LWPntID *p = (LWPntID *)bsearch(&id, _aidPntIDs, _ctPntIDs, sizeof(id), qsort_CompareIDs);
if (p==NULL) {
assert(false);
return 0;
} else {
return p-_aidPntIDs;
}
}
int GetPolIndex(LWPolID id)
{
LWPolID *p = (LWPolID *)bsearch(&id, _aidPolIDs, _ctPolIDs, sizeof(id), qsort_CompareIDs);
if (p==NULL) {
assert(false);
return 0;
} else {
return p-_aidPolIDs;
}
}
int EnumPnts(void *, LWPntID id)
{
_aidPntIDs[_iPnt++] = id;
return 0;
}
int EnumPols(void *, LWPolID id)
{
_aidPolIDs[_iPol++] = id;
return 0;
}
// fill base vertex coordinates (without morphing)
void FillOriginalVertexCoords(void)
{
// for each vertex
{for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
// get the coords
_pmesh->pntBasePos(_pmesh, _aidPntIDs[iPnt], _avPnts[iPnt]);
}}
}
// fill vertex coordinates with relative morphing
void FillRelativeMorphVertexCoords(const char *strRelMorphMapName)
{
// fill base vertex coordinates (without morphing)
FillOriginalVertexCoords();
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_MORF, strRelMorphMapName);
_pmesh->pntVSelect(_pmesh, pMap);
// for each vertex
{for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
// if morphed
float v[3];
if (_pmesh->pntVGet(_pmesh, _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(const char *strAbsMorphMapName)
{
// fill base vertex coordinates (without morphing)
FillOriginalVertexCoords();
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_SPOT, strAbsMorphMapName);
_pmesh->pntVSelect(_pmesh, pMap);
// for each vertex
{for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
// if morphed
float v[3];
if (_pmesh->pntVGet(_pmesh, _aidPntIDs[iPnt], v)) {
// apply the morph
_avPnts[iPnt][0] = v[0];
_avPnts[iPnt][1] = v[1];
_avPnts[iPnt][2] = v[2];
}
}}
}
// calculate mesh normals using local vertex coordinates (to be able to calculate normals for morphmaps)
void MakeNormals(void)
{
// generate polygon normals
{for(int iPol=0; iPol<_ctPolIDs; iPol++) {
LWPolID idPol = _aidPolIDs[iPol];
int ctInThisPol = _pmesh->polSize(_pmesh, idPol);
if (ctInThisPol<3) {
_avPolNormals[iPol][0] = 0.0f;
_avPolNormals[iPol][1] = 0.0f;
_avPolNormals[iPol][2] = 0.0f;
}
LWPntID idPnt0 = _pmesh->polVertex(_pmesh, idPol, ctInThisPol-1);
LWPntID idPnt1 = _pmesh->polVertex(_pmesh, idPol, 0);
LWPntID idPnt2 = _pmesh->polVertex(_pmesh, idPol, 1);
float v0[3], v1[3], v2[3];
_pmesh->pntBasePos(_pmesh, idPnt0, v0);
_pmesh->pntBasePos(_pmesh, idPnt1, v1);
_pmesh->pntBasePos(_pmesh, idPnt2, v2);
float d1[3], d2[3];
for (int i=0; i<3; i++) {
d1[i] = v2[i] - v1[i];
d2[i] = v0[i] - v1[i];
}
cross(d1, d2, _avPolNormals[iPol]);
normalize( _avPolNormals[iPol]);
}}
// 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(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(_appPntPols[iPntPol].pp_idPol);
vNormalSum[0] += _avPolNormals[iPol][0];
vNormalSum[1] += _avPolNormals[iPol][1];
vNormalSum[2] += _avPolNormals[iPol][2];
idLastPnt=idThis;
}}
int iLastPnt = GetPntIndex(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(void)
{
// extract point and poly ids, so we can walk them later
_ctPntIDs = _pmesh->numPoints(_pmesh);
_aidPntIDs = (LWPntID*)malloc(_ctPntIDs*sizeof(LWPntID));
_iPnt = 0;
_pmesh->scanPoints(_pmesh, EnumPnts, NULL);
qsort(_aidPntIDs, _ctPntIDs, sizeof(LWPntID), qsort_CompareIDs);
_ctPolIDs = _pmesh->numPolygons(_pmesh);
_aidPolIDs = (LWPolID*)malloc(_ctPolIDs*sizeof(LWPolID));
_iPol = 0;
_pmesh->scanPolys(_pmesh, EnumPols, NULL);
qsort(_aidPolIDs, _ctPolIDs, sizeof(LWPolID), qsort_CompareIDs);
// find the total number of points in all polygons
_ctPolPnts = 0;
for(int iPol=0; iPol<_ctPolIDs; iPol++) {
int ct = _pmesh->polSize(_pmesh, _aidPolIDs[iPol]);
if (ct!=3) {
_msg->error("All objects must be triangles!", NULL);
}
_ctPolPnts += ct;
}
_appPolPnts = (PolPnt *)malloc(_ctPolPnts*sizeof(PolPnt));
_appPntPols = (PolPnt *)malloc(_ctPolPnts*sizeof(PolPnt));
// fill in all point and polygon combinations
{int iPolPnt = 0;
for(int iPol=0; iPol<_ctPolIDs; iPol++) {
LWPolID idPol = _aidPolIDs[iPol];
int ctInThisPol = _pmesh->polSize(_pmesh, idPol);
for (int iPnt=0; iPnt<ctInThisPol; iPnt++) {
LWPntID idPnt = _pmesh->polVertex(_pmesh, idPol, iPnt);
_appPolPnts[iPolPnt].pp_idPol = idPol;
_appPolPnts[iPolPnt].pp_idPnt = idPnt;
iPolPnt++;
}
}}
// copy to per-point array and sort by points
memcpy(_appPntPols, _appPolPnts, _ctPolPnts*sizeof(PolPnt));
qsort(_appPntPols, _ctPolPnts, sizeof(PolPnt), qsort_ComparePolPntsByPnt);
// 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();
MakeNormals();
// list all the uvmaps used by this object
_ctUVMapNames = _obf->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 = _obf->vmapName(LWVMAP_TXUV, iUVMap);
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_TXUV, strName);
_pmesh->pntVSelect(_pmesh, pMap);
bool bExists = false;
for(int iPnt=0; iPnt<_ctPntIDs; iPnt++) {
float v[2];
if (_pmesh->pntVGet(_pmesh, _aidPntIDs[iPnt], v)) {
bExists = true;
break;
}
}
if (bExists) {
_astrUVMapNames[_ctUsedUVMapNames++] = strName;
}
}}
// list all the weightmaps used by this object
_ctWeightMapNames = _obf->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 = _obf->vmapName(LWVMAP_WGHT, iWeightMap);
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_WGHT, strName);
_pmesh->pntVSelect(_pmesh, pMap);
int ct = 0;
// for each polygonvertex
for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// get the weight
float v[1];
if (_pmesh->pntVGet(_pmesh, _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 = _obf->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 = _obf->vmapName(LWVMAP_MORF, iRelMorphMap);
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_MORF, strName);
_pmesh->pntVSelect(_pmesh, pMap);
int ct = 0;
// for each polygonvertex
for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// get the morphpos
float v[3];
if (_pmesh->pntVGet(_pmesh, _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 = _obf->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 = _obf->vmapName(LWVMAP_SPOT, iAbsMorphMap);
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_SPOT, strName);
_pmesh->pntVSelect(_pmesh, pMap);
int ct = 0;
// for each polygonvertex
for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// get the morphpos
float v[3];
if (_pmesh->pntVGet(_pmesh, _appPolPnts[iPolPnt].pp_idPnt, v)) {
ct++;
}
}
if (ct>0) {
_astrAbsMorphMapNames[_ctUsedAbsMorphMapNames] = strName;
}
_actAbsMorphMapCounts[_ctUsedAbsMorphMapNames] = ct;
_ctUsedAbsMorphMapNames++;
}}
}
FILE *_f = NULL;
int ExportMesh(LWXPanelID pan)
{
// is mesh face forward
int iFaceForward = *(int*)_xpanf->formGet( pan, ID_FACEFORWARD);
// !!!! make it work with a selected object, not the first one in scene
ReloadGlobalObjects();
bool bExportOnlySelected = false;
// count selected objects
int ctSelectedMeshed = 0;
int ctMeshes=0;
_objid = _iti->first(LWI_OBJECT,0);
while(_objid != LWITEM_NULL)
{
if(_iti->type(_objid) == LWI_OBJECT)
{
_pmesh = _obi->meshInfo(_objid, 0);
if(_pmesh != NULL)
{
if(_ifi->itemFlags(_objid) & LWITEMF_SELECTED)
{
ctSelectedMeshed++;
}
}
ctMeshes++;
}
_objid = _iti->next(_objid);
}
// get the first object in the scene
_objid = _iti->first(LWI_OBJECT,0);
if (!_objid)
{
_msg->error("No object in the scene.", NULL);
return AFUNC_OK;
}
// if some objects are selected export only them
if(ctSelectedMeshed > 0) bExportOnlySelected = true;
// dont ask to export all meshes if only one mesh in the scene
if(ctSelectedMeshed == 0)
{
if(ctMeshes > 1)
{
if(_msg->yesNo("No objects selected","Export all meshes?",NULL) == 0)
return AFUNC_OK;
bExportOnlySelected = false;
}
}
// loop each mesh in scene
while(_objid != LWITEM_NULL)
{
// get its mesh
_pmesh = _obi->meshInfo(_objid, 0);
if(_pmesh == NULL)
{
_objid = _iti->next(_objid);
continue;
}
if(bExportOnlySelected)
{
if(!(_ifi->itemFlags(_objid) & LWITEMF_SELECTED))
{
_objid = _iti->next(_objid);
continue;
}
}
// get mesh name
_strFileName = strdup(_obi->filename(_objid));
// extract polygon and point info
ExtractMeshData();
// open the file to print into
char fnmOut[256];
strcpy(fnmOut, _strFileName);
char *pchDot = strrchr(fnmOut, '.');
if (pchDot!=NULL) {
strcpy(pchDot, ".am");
}
_f = fopen(fnmOut, "w");
if (_f==NULL) {
_msg->error("Can't open file", fnmOut);
goto end;
}
// write the mesh header
fprintf(_f, "SE_MESH %s;\n\n",SE_ANIM_VER);
if(iFaceForward==ML_HALF_FACE_FORWARD) {
fprintf(_f, "HALF_FACE_FORWARD TRUE;\n\n");
} else if(iFaceForward==ML_FULL_FACE_FORWARD) {
fprintf(_f, "FULL_FACE_FORWARD TRUE;\n\n");
}
// write the vertex header
fprintf(_f, "VERTICES %d\n", _ctPolPnts);
fprintf(_f, "{\n");
// for each polygonvertex
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// get the coords
float v[3];
_pmesh->pntBasePos(_pmesh, _appPolPnts[iPolPnt].pp_idPnt, v);
fprintf(_f, " %g, %g, %g;\n", v[0], v[1], -v[2]);
}}
fprintf(_f, "}\n\n");
// write the normal header
fprintf(_f, "NORMALS %d\n", _ctPolPnts);
fprintf(_f, "{\n");
// for each polygonvertex
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// get the normal
int iPnt = GetPntIndex(_appPolPnts[iPolPnt].pp_idPnt);
fprintf(_f, " %g, %g, %g;\n", _avPntNormals[iPnt][0], _avPntNormals[iPnt][1], -_avPntNormals[iPnt][2]);
}}
fprintf(_f, "}\n\n");
// write the uvmaps header
fprintf(_f, "UVMAPS %d\n", _ctUsedUVMapNames);
fprintf(_f, "{\n");
// for each uvmap
if (_ctUsedUVMapNames == 0) {
_msg->info("No UV maps in the scene!",NULL);
}
{for(int iUVMap=0; iUVMap<_ctUsedUVMapNames; iUVMap++) {
fprintf(_f, " {\n");
const char *strUVMap = _astrUVMapNames[iUVMap];
fprintf(_f, " NAME \"%s\";\n", strUVMap);
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_TXUV, strUVMap);
_pmesh->pntVSelect(_pmesh, pMap);
fprintf(_f, " TEXCOORDS %d\n", _ctPolPnts);
fprintf(_f, " {\n");
// for each polygonvertex
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// get the coords
float v[2];
if (_pmesh->pntVPGet(_pmesh, _appPolPnts[iPolPnt].pp_idPnt, _appPolPnts[iPolPnt].pp_idPol, v)) {
} else if (_pmesh->pntVGet(_pmesh, _appPolPnts[iPolPnt].pp_idPnt, v)) {
} else {
v[0] = 0.0f;
v[1] = 0.0f;
}
fprintf(_f, " %g, %g;\n", v[0], 1.0f-v[1]);
}}
fprintf(_f, " }\n");
fprintf(_f, " }\n");
}}
fprintf(_f, "}\n\n");
// get surfaces
_asurSurfaces = _srf->byObject(_strFileName);
// count the surfaces
_ctSurfs = 0;
while(_asurSurfaces[_ctSurfs]!=NULL) {
_ctSurfs++;
}
// write the surfaces header
fprintf(_f, "SURFACES %d\n", _ctSurfs);
fprintf(_f, "{\n");
// for each surface
{for(int iSurf=0; iSurf<_ctSurfs; iSurf++) {
fprintf(_f, " {\n");
const char *strSurf = _srf->name(_asurSurfaces[iSurf]);
fprintf(_f, " NAME \"%s\";\n", strSurf);
// count the polygons
int iSurfPols = 0;
{for(int i=0; i<_ctPolIDs; i++) {
if (strcmp(_pmesh->polTag(_pmesh, _aidPolIDs[i], LWPTAG_SURF), strSurf)==0) {
iSurfPols++;
}
}}
// write the polygon set header
fprintf(_f, " TRIANGLE_SET %d\n", iSurfPols);
fprintf(_f, " {\n");
// for each polygon
for(int iTri=0; iTri<_ctPolIDs; iTri++) {
LWPolID idPol = _aidPolIDs[iTri];
// if not in this surface
if (strcmp(_pmesh->polTag(_pmesh, idPol, LWPTAG_SURF), strSurf)!=0) {
// skip it
continue;
}
// assert(_appPolPnts[iTri*3+0].pp_idPol == idPol);
// assert(_appPolPnts[iTri*3+1].pp_idPol == idPol);
// assert(_appPolPnts[iTri*3+2].pp_idPol == idPol);
fprintf(_f, " %d, %d, %d;\n", iTri*3+2, iTri*3+1, iTri*3+0);
// GetPntIndex(_appPolPnts[iTri*3+0].pp_idPnt),
// GetPntIndex(_appPolPnts[iTri*3+1].pp_idPnt),
// GetPntIndex(_appPolPnts[iTri*3+2].pp_idPnt));
}
fprintf(_f, " }\n");
fprintf(_f, " }\n");
}}
fprintf(_f, "}\n");
// write the weightmaps header
fprintf(_f, "WEIGHTS %d\n", _ctUsedWeightMapNames);
fprintf(_f, "{\n");
// for each weightmap
{for(int iWeightMap=0; iWeightMap<_ctUsedWeightMapNames; iWeightMap++) {
fprintf(_f, " {\n");
const char *strWeightMap = _astrWeightMapNames[iWeightMap];
fprintf(_f, " NAME \"%s\";\n", strWeightMap);
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_WGHT, strWeightMap);
_pmesh->pntVSelect(_pmesh, pMap);
fprintf(_f, " WEIGHT_SET %d\n", _actWeightMapCounts[iWeightMap]);
fprintf(_f, " {\n");
// for each polygonvertex
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// get the coords
float v[1];
if (_pmesh->pntVGet(_pmesh, _appPolPnts[iPolPnt].pp_idPnt, v) && v[0]!=0.0f) {
if (v[0] < 0) {
_msg->error("Weight map value lesser than zero!",NULL);
} else {
fprintf(_f, " { %d; %g; }\n", iPolPnt, v[0]);
}
}
}}
fprintf(_f, " }\n");
fprintf(_f, " }\n");
}}
fprintf(_f, "}\n\n");
// write the morphmaps header
fprintf(_f, "MORPHS %d\n", _ctUsedRelMorphMapNames+_ctUsedAbsMorphMapNames);
fprintf(_f, "{\n");
// for each relmorphmap
{for(int iRelMorphMap=0; iRelMorphMap<_ctUsedRelMorphMapNames; iRelMorphMap++) {
const char *strRelMorphMap = _astrRelMorphMapNames[iRelMorphMap];
// calculate mesh normals using the given morphmap
FillRelativeMorphVertexCoords(strRelMorphMap);
MakeNormals();
fprintf(_f, " {\n");
fprintf(_f, " NAME \"%s\";\n", strRelMorphMap);
fprintf(_f, " RELATIVE TRUE;\n");
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_MORF, strRelMorphMap);
_pmesh->pntVSelect(_pmesh, pMap);
fprintf(_f, " MORPH_SET %d\n", _actRelMorphMapCounts[iRelMorphMap]);
fprintf(_f, " {\n");
// for each polygonvertex
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// if morphed here
float vRel[3];
if (_pmesh->pntVGet(_pmesh, _appPolPnts[iPolPnt].pp_idPnt, vRel)) {
// write the coords and normal
int iPnt = GetPntIndex(_appPolPnts[iPolPnt].pp_idPnt);
fprintf(_f, " { %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(_f, " }\n");
fprintf(_f, " }\n");
}}
// for each absmorphmap
{for(int iAbsMorphMap=0; iAbsMorphMap<_ctUsedAbsMorphMapNames; iAbsMorphMap++) {
const char *strAbsMorphMap = _astrAbsMorphMapNames[iAbsMorphMap];
// calculate mesh normals using the given morphmap
FillAbsoluteMorphVertexCoords(strAbsMorphMap);
MakeNormals();
fprintf(_f, " {\n");
fprintf(_f, " NAME \"%s\";\n", strAbsMorphMap);
fprintf(_f, " RELATIVE FALSE;\n");
void *pMap = _pmesh->pntVLookup(_pmesh, LWVMAP_SPOT, strAbsMorphMap);
_pmesh->pntVSelect(_pmesh, pMap);
fprintf(_f, " MORPH_SET %d\n", _actAbsMorphMapCounts[iAbsMorphMap]);
fprintf(_f, " {\n");
// for each polygonvertex
{for(int iPolPnt=0; iPolPnt<_ctPolPnts; iPolPnt++) {
// if morphed here
float vRel[3];
if (_pmesh->pntVGet(_pmesh, _appPolPnts[iPolPnt].pp_idPnt, vRel)) {
// write the coords and normal
int iPnt = GetPntIndex(_appPolPnts[iPolPnt].pp_idPnt);
fprintf(_f, " { %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(_f, " }\n");
fprintf(_f, " }\n");
}}
fprintf(_f, "}\n\n");
fprintf(_f, "SE_MESH_END;\n");
_msg->info("Saved:", fnmOut);
end:
// close and free everything
if (_f!=NULL) {
fclose(_f);
_f=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;
}
// get next mesh obj
_objid = _iti->next(_objid);
}
return AFUNC_OK;
}