This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/collada/GeometryExporter.cpp
Brecht Van Lommel 2345efc6c5 Patch #29336: renaming UV (Texture) Layer to UV Map in the user interface,
by Gaia Clary.

Rationale: the name was confusing and not always used consistently, and this
map itself is not something that can be layered, rather the map can be used
as texture coordinates in some layered setup.

The original intent was to indicate this contained more than just UV's, but
the game engine settings have already been moved out, and apparently users
didn't really get this from the name anyway.
2011-11-23 17:25:25 +00:00

490 lines
13 KiB
C++

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* 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.
*
* Contributor(s): Chingiz Dyussenov, Arystanbek Dyussenov, Jan Diederich, Tod Liverseed,
* Nathan Letwory
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/collada/GeometryExporter.cpp
* \ingroup collada
*/
#include <sstream>
#include "COLLADASWPrimitves.h"
#include "COLLADASWSource.h"
#include "COLLADASWVertices.h"
#include "COLLADABUUtils.h"
#include "GeometryExporter.h"
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
#include "BKE_material.h"
#include "collada_internal.h"
// TODO: optimize UV sets by making indexed list with duplicates removed
GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryGeometries(sw), export_settings(export_settings) {}
void GeometryExporter::exportGeom(Scene *sce)
{
openLibrary();
mScene = sce;
GeometryFunctor gf;
gf.forEachMeshObjectInScene<GeometryExporter>(sce, *this, this->export_settings->selected);
closeLibrary();
}
void GeometryExporter::operator()(Object *ob)
{
// XXX don't use DerivedMesh, Mesh instead?
#if 0
DerivedMesh *dm = mesh_get_derived_final(mScene, ob, CD_MASK_BAREMESH);
#endif
Mesh *me = (Mesh*)ob->data;
std::string geom_id = get_geometry_id(ob);
std::vector<Normal> nor;
std::vector<Face> norind;
// Skip if linked geometry was already exported from another reference
if (exportedGeometry.find(geom_id) != exportedGeometry.end())
return;
exportedGeometry.insert(geom_id);
bool has_color = (bool)CustomData_has_layer(&me->fdata, CD_MCOL);
create_normals(nor, norind, me);
// openMesh(geoId, geoName, meshId)
openMesh(geom_id);
// writes <source> for vertex coords
createVertsSource(geom_id, me);
// writes <source> for normal coords
createNormalsSource(geom_id, me, nor);
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
// writes <source> for uv coords if mesh has uv coords
if (has_uvs)
createTexcoordsSource(geom_id, me);
if (has_color)
createVertexColorSource(geom_id, me);
// <vertices>
COLLADASW::Vertices verts(mSW);
verts.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX));
COLLADASW::InputList &input_list = verts.getInputList();
COLLADASW::Input input(COLLADASW::InputSemantic::POSITION, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
input_list.push_back(input);
verts.add();
// XXX slow
if (ob->totcol) {
for(int a = 0; a < ob->totcol; a++) {
createPolylist(a, has_uvs, has_color, ob, geom_id, norind);
}
}
else {
createPolylist(0, has_uvs, has_color, ob, geom_id, norind);
}
closeMesh();
if (me->flag & ME_TWOSIDED) {
mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
}
closeGeometry();
#if 0
dm->release(dm);
#endif
}
// powerful because it handles both cases when there is material and when there's not
void GeometryExporter::createPolylist(short material_index,
bool has_uvs,
bool has_color,
Object *ob,
std::string& geom_id,
std::vector<Face>& norind)
{
Mesh *me = (Mesh*)ob->data;
MFace *mfaces = me->mface;
int totfaces = me->totface;
// <vcount>
int i;
int faces_in_polylist = 0;
std::vector<unsigned long> vcount_list;
// count faces with this material
for (i = 0; i < totfaces; i++) {
MFace *f = &mfaces[i];
if (f->mat_nr == material_index) {
faces_in_polylist++;
if (f->v4 == 0) {
vcount_list.push_back(3);
}
else {
vcount_list.push_back(4);
}
}
}
// no faces using this material
if (faces_in_polylist == 0) {
fprintf(stderr, "%s: no faces use material %d\n", id_name(ob).c_str(), material_index);
return;
}
Material *ma = ob->totcol ? give_current_material(ob, material_index + 1) : NULL;
COLLADASW::Polylist polylist(mSW);
// sets count attribute in <polylist>
polylist.setCount(faces_in_polylist);
// sets material name
if (ma) {
std::ostringstream ostr;
ostr << translate_id(id_name(ma)) << material_index+1;
polylist.setMaterial(ostr.str());
}
COLLADASW::InputList &til = polylist.getInputList();
// creates <input> in <polylist> for vertices
COLLADASW::Input input1(COLLADASW::InputSemantic::VERTEX, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::VERTEX), 0);
// creates <input> in <polylist> for normals
COLLADASW::Input input2(COLLADASW::InputSemantic::NORMAL, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL), 1);
til.push_back(input1);
til.push_back(input2);
// if mesh has uv coords writes <input> for TEXCOORD
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
for (i = 0; i < num_layers; i++) {
// char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
COLLADASW::Input input3(COLLADASW::InputSemantic::TEXCOORD,
makeUrl(makeTexcoordSourceId(geom_id, i)),
2, // offset always 2, this is only until we have optimized UV sets
i // set number equals UV map index
);
til.push_back(input3);
}
if (has_color) {
COLLADASW::Input input4(COLLADASW::InputSemantic::COLOR, getUrlBySemantics(geom_id, COLLADASW::InputSemantic::COLOR), has_uvs ? 3 : 2);
til.push_back(input4);
}
// sets <vcount>
polylist.setVCountList(vcount_list);
// performs the actual writing
polylist.prepareToAppendValues();
// <p>
int texindex = 0;
for (i = 0; i < totfaces; i++) {
MFace *f = &mfaces[i];
if (f->mat_nr == material_index) {
unsigned int *v = &f->v1;
unsigned int *n = &norind[i].v1;
for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
polylist.appendValues(v[j]);
polylist.appendValues(n[j]);
if (has_uvs)
polylist.appendValues(texindex + j);
if (has_color)
polylist.appendValues(texindex + j);
}
}
texindex += 3;
if (f->v4 != 0)
texindex++;
}
polylist.finish();
}
// creates <source> for positions
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
{
#if 0
int totverts = dm->getNumVerts(dm);
MVert *verts = dm->getVertArray(dm);
#endif
int totverts = me->totvert;
MVert *verts = me->mvert;
COLLADASW::FloatSourceF source(mSW);
source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION));
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::POSITION) +
ARRAY_ID_SUFFIX);
source.setAccessorCount(totverts);
source.setAccessorStride(3);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("X");
param.push_back("Y");
param.push_back("Z");
/*main function, it creates <source id = "">, <float_array id = ""
count = ""> */
source.prepareToAppendValues();
//appends data to <float_array>
int i = 0;
for (i = 0; i < totverts; i++) {
source.appendValues(verts[i].co[0], verts[i].co[1], verts[i].co[2]);
}
source.finish();
}
void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
{
if (!CustomData_has_layer(&me->fdata, CD_MCOL))
return;
MFace *f;
int totcolor = 0, i, j;
for (i = 0, f = me->mface; i < me->totface; i++, f++)
totcolor += f->v4 ? 4 : 3;
COLLADASW::FloatSourceF source(mSW);
source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR));
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::COLOR) + ARRAY_ID_SUFFIX);
source.setAccessorCount(totcolor);
source.setAccessorStride(3);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("R");
param.push_back("G");
param.push_back("B");
source.prepareToAppendValues();
int index = CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
MCol *mcol = (MCol*)me->fdata.layers[index].data;
MCol *c = mcol;
for (i = 0, f = me->mface; i < me->totface; i++, c += 4, f++)
for (j = 0; j < (f->v4 ? 4 : 3); j++)
source.appendValues(c[j].b / 255.0f, c[j].g / 255.0f, c[j].r / 255.0f);
source.finish();
}
std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index)
{
char suffix[20];
sprintf(suffix, "-%d", layer_index);
return getIdBySemantics(geom_id, COLLADASW::InputSemantic::TEXCOORD) + suffix;
}
//creates <source> for texcoords
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
{
#if 0
int totfaces = dm->getNumFaces(dm);
MFace *mfaces = dm->getFaceArray(dm);
#endif
int totfaces = me->totface;
MFace *mfaces = me->mface;
int totuv = 0;
int i;
// count totuv
for (i = 0; i < totfaces; i++) {
MFace *f = &mfaces[i];
if (f->v4 == 0) {
totuv+=3;
}
else {
totuv+=4;
}
}
int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
// write <source> for each layer
// each <source> will get id like meshName + "map-channel-1"
for (int a = 0; a < num_layers; a++) {
MTFace *tface = (MTFace*)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
// char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
COLLADASW::FloatSourceF source(mSW);
std::string layer_id = makeTexcoordSourceId(geom_id, a);
source.setId(layer_id);
source.setArrayId(layer_id + ARRAY_ID_SUFFIX);
source.setAccessorCount(totuv);
source.setAccessorStride(2);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("S");
param.push_back("T");
source.prepareToAppendValues();
for (i = 0; i < totfaces; i++) {
MFace *f = &mfaces[i];
for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
source.appendValues(tface[i].uv[j][0],
tface[i].uv[j][1]);
}
}
source.finish();
}
}
//creates <source> for normals
void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor)
{
#if 0
int totverts = dm->getNumVerts(dm);
MVert *verts = dm->getVertArray(dm);
#endif
COLLADASW::FloatSourceF source(mSW);
source.setId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL));
source.setArrayId(getIdBySemantics(geom_id, COLLADASW::InputSemantic::NORMAL) +
ARRAY_ID_SUFFIX);
source.setAccessorCount((unsigned long)nor.size());
source.setAccessorStride(3);
COLLADASW::SourceBase::ParameterNameList &param = source.getParameterNameList();
param.push_back("X");
param.push_back("Y");
param.push_back("Z");
source.prepareToAppendValues();
std::vector<Normal>::iterator it;
for (it = nor.begin(); it != nor.end(); it++) {
Normal& n = *it;
source.appendValues(n.x, n.y, n.z);
}
source.finish();
}
void GeometryExporter::create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me)
{
int i, j, v;
MVert *vert = me->mvert;
std::map<unsigned int, unsigned int> nshar;
for (i = 0; i < me->totface; i++) {
MFace *fa = &me->mface[i];
Face f;
unsigned int *nn = &f.v1;
unsigned int *vv = &fa->v1;
memset(&f, 0, sizeof(f));
v = fa->v4 == 0 ? 3 : 4;
if (!(fa->flag & ME_SMOOTH)) {
Normal n;
if (v == 4)
normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co);
else
normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co);
nor.push_back(n);
}
for (j = 0; j < v; j++) {
if (fa->flag & ME_SMOOTH) {
if (nshar.find(*vv) != nshar.end())
*nn = nshar[*vv];
else {
Normal n = {
vert[*vv].no[0]/32767.0,
vert[*vv].no[1]/32767.0,
vert[*vv].no[2]/32767.0
};
nor.push_back(n);
*nn = (unsigned int)nor.size() - 1;
nshar[*vv] = *nn;
}
vv++;
}
else {
*nn = (unsigned int)nor.size() - 1;
}
nn++;
}
ind.push_back(f);
}
}
std::string GeometryExporter::getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix) {
return geom_id + getSuffixBySemantic(type) + other_suffix;
}
COLLADASW::URI GeometryExporter::getUrlBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix) {
std::string id(getIdBySemantics(geom_id, type, other_suffix));
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
}
COLLADASW::URI GeometryExporter::makeUrl(std::string id)
{
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
}
/* int GeometryExporter::getTriCount(MFace *faces, int totface) {
int i;
int tris = 0;
for (i = 0; i < totface; i++) {
// if quad
if (faces[i].v4 != 0)
tris += 2;
else
tris++;
}
return tris;
}*/