24 #include "FCDocument/FCDAsset.h"
25 #include "FCDocument/FCDocument.h"
26 #include "FCDocument/FCDocumentTools.h"
27 #include "FCDocument/FCDController.h"
28 #include "FCDocument/FCDControllerInstance.h"
29 #include "FCDocument/FCDGeometry.h"
30 #include "FCDocument/FCDGeometryMesh.h"
31 #include "FCDocument/FCDGeometryPolygons.h"
32 #include "FCDocument/FCDGeometryPolygonsInput.h"
33 #include "FCDocument/FCDGeometryPolygonsTools.h"
34 #include "FCDocument/FCDGeometrySource.h"
35 #include "FCDocument/FCDSceneNode.h"
36 #include "FCDocument/FCDSkinController.h"
67 float l = vec.Length();
69 return FMVector3(vec.x/l, vec.y/l, vec.z/l);
71 return FMVector3(1.0f, 0.0f, 0.0f);
74 static void AddStaticPropPoints(std::vector<PropPoint> &propPoints,
const FMMatrix44& upAxisTransform, FCDSceneNode* node)
76 if (node->GetName().find(
"prop-") == 0 || node->GetName().find(
"prop_") == 0)
79 std::string propPointName (node->GetName().substr(5));
81 Log(
LOG_INFO,
"Adding prop point %s", propPointName.c_str());
86 FMMatrix44 transform = upAxisTransform * node->CalculateWorldTransform();
89 memcpy(matrix, transform.Transposed().m,
sizeof(matrix));
100 { parts.
t.
x, parts.
t.
z, parts.
t.
y },
107 { parts.
q.
x, parts.
q.
z, parts.
q.
y, -parts.
q.
w },
111 propPoints.push_back(p);
115 for (
size_t i = 0; i < node->GetChildrenCount(); ++i)
135 if (converter.
GetInstance().GetEntity()->GetType() == FCDEntity::GEOMETRY)
144 std::vector<VertexBlend> boneWeights;
145 std::vector<BoneTransform> boneTransforms;
146 std::vector<PropPoint> propPoints;
150 FCDGeometryPolygonsInput* inputPosition = polys->FindInput(FUDaeGeometryInput::POSITION);
151 FCDGeometryPolygonsInput* inputNormal = polys->FindInput(FUDaeGeometryInput::NORMAL);
153 const uint32* indicesCombined = inputPosition->GetIndices();
154 size_t indicesCombinedCount = inputPosition->GetIndexCount();
157 FCDGeometrySource* sourcePosition = inputPosition->GetSource();
158 FCDGeometrySource* sourceNormal = inputNormal ->GetSource();
160 FCDGeometrySourceList texcoordSources;
161 polys->GetParent()->FindSourcesByType(FUDaeGeometryInput::TEXCOORD, texcoordSources);
163 float* dataPosition = sourcePosition->GetData();
164 float* dataNormal = sourceNormal ->GetData();
165 size_t vertexCount = sourcePosition->GetDataCount() / 3;
166 assert(sourcePosition->GetDataCount() == vertexCount*3);
167 assert(sourceNormal ->GetDataCount() == vertexCount*3);
169 std::vector<float*> dataTexcoords;
170 for (
size_t i = 0; i < texcoordSources.size(); ++i)
172 dataTexcoords.push_back(texcoordSources[i]->GetData());
189 if (converter.
IsYUp())
193 upAxisTransform = FMMatrix44::XAxisRotationMatrix(1.57f);
198 WritePMD(output, indicesCombined, indicesCombinedCount, dataPosition, dataNormal, dataTexcoords, vertexCount, boneWeights, boneTransforms, propPoints);
200 else if (converter.
GetInstance().GetType() == FCDEntityInstance::CONTROLLER)
204 FCDControllerInstance& controllerInstance =
static_cast<FCDControllerInstance&
>(converter.
GetInstance());
210 assert(converter.
GetInstance().GetEntity()->GetType() == FCDEntity::CONTROLLER);
211 FCDController* controller =
static_cast<FCDController*
>(converter.
GetInstance().GetEntity());
213 FCDSkinController* skin = controller->GetSkinController();
214 REQUIRE(skin != NULL,
"is skin controller");
221 size_t jointCount = std::min(skin->GetJointCount(), controllerInstance.GetJointCount());
222 if (skin->GetJointCount() != controllerInstance.GetJointCount())
224 Log(
LOG_WARNING,
"Mismatched bone counts (skin has %d, skeleton has %d)",
225 skin->GetJointCount(), controllerInstance.GetJointCount());
226 for (
size_t i = 0; i < skin->GetJointCount(); ++i)
227 Log(
LOG_INFO,
"Skin joint %d: %s", i, skin->GetJoint(i)->GetId().c_str());
228 for (
size_t i = 0; i < controllerInstance.GetJointCount(); ++i)
229 Log(
LOG_INFO,
"Skeleton joint %d: %s", i, controllerInstance.GetJoint(i)->GetName().c_str());
233 FCDGeometry* baseGeometry = controller->GetBaseGeometry();
234 REQUIRE(baseGeometry != NULL,
"controller has base geometry");
247 bool hasComplainedAboutNonexistentJoints =
false;
249 std::vector<VertexBlend> boneWeights;
251 const FCDSkinControllerVertex* vertexInfluences = skin->GetVertexInfluences();
252 for (
size_t i = 0; i < skin->GetInfluenceCount(); ++i)
260 if (vertexInfluences[i].GetPairCount() == 0)
267 influences.
bones[0] = (uint8)jointCount;
271 for (
size_t j = 0; j < vertexInfluences[i].GetPairCount(); ++j)
273 if (vertexInfluences[i].GetPair(j)->jointIndex == -1)
288 influences.
bones[j] = (uint8)jointCount;
289 influences.
weights[j] = vertexInfluences[i].GetPair(j)->weight;
296 uint32 jointIdx = vertexInfluences[i].GetPair(j)->jointIndex;
297 REQUIRE(jointIdx < 0xFE,
"sensible number of joints (<254)");
300 FCDSceneNode* joint = NULL;
301 if (jointIdx < controllerInstance.GetJointCount())
302 joint = controllerInstance.GetJoint(jointIdx);
307 if (! hasComplainedAboutNonexistentJoints)
310 hasComplainedAboutNonexistentJoints =
true;
316 int boneId = skeleton.
GetBoneID(joint->GetName().c_str());
321 Log(
LOG_ERROR,
"Vertex influenced by unrecognised bone '%s'", joint->GetName().c_str());
325 influences.
bones[j] = (uint8)boneId;
326 influences.
weights[j] = vertexInfluences[i].GetPair(j)->weight;
330 boneWeights.push_back(influences);
336 std::vector<BoneTransform> boneTransforms (skeleton.
GetBoneCount(), boneDefault);
338 for (
size_t i = 0; i < jointCount; ++i)
340 FCDSceneNode* joint = controllerInstance.GetJoint(i);
342 int boneId = skeleton.
GetRealBoneID(joint->GetName().c_str());
350 FMMatrix44 bindPose = skin->GetJoint(i)->GetBindPoseInverse().Inverted();
353 memcpy(matrix, bindPose.Transposed().m,
sizeof(matrix));
360 { parts.
t.
x, parts.
t.
y, parts.
t.
z },
361 { parts.
q.
x, parts.
q.
y, parts.
q.
z, parts.
q.
w }
364 boneTransforms[boneId] = b;
371 std::vector<PropPoint> propPoints;
374 for (
size_t i = 0; i < jointCount; ++i)
376 FCDSceneNode* joint = controllerInstance.GetJoint(i);
378 int boneId = skeleton.
GetBoneID(joint->GetName().c_str());
386 for (
size_t j = 0; j < joint->GetChildrenCount(); ++j)
388 FCDSceneNode* child = joint->GetChild(j);
389 if (child->GetName().find(
"prop-") != 0 && child->GetName().find(
"prop_") != 0)
395 std::string propPointName (child->GetName().substr(5));
397 Log(
LOG_INFO,
"Adding prop point %s", propPointName.c_str());
401 FMMatrix44 localTransform = child->ToMatrix();
404 memcpy(matrix, localTransform.Transposed().m,
sizeof(matrix));
413 { parts.
t.
x, parts.
t.
y, parts.
t.
z },
414 { parts.
q.
x, parts.
q.
y, parts.
q.
z, parts.
q.
w },
417 propPoints.push_back(p);
423 FCDGeometryPolygonsInput* inputPosition = polys->FindInput(FUDaeGeometryInput::POSITION);
424 FCDGeometryPolygonsInput* inputNormal = polys->FindInput(FUDaeGeometryInput::NORMAL);
426 const uint32* indicesCombined = inputPosition->GetIndices();
427 size_t indicesCombinedCount = inputPosition->GetIndexCount();
430 FCDGeometrySource* sourcePosition = inputPosition->GetSource();
431 FCDGeometrySource* sourceNormal = inputNormal ->GetSource();
433 FCDGeometrySourceList texcoordSources;
434 polys->GetParent()->FindSourcesByType(FUDaeGeometryInput::TEXCOORD, texcoordSources);
436 float* dataPosition = sourcePosition->GetData();
437 float* dataNormal = sourceNormal ->GetData();
438 size_t vertexCount = sourcePosition->GetDataCount() / 3;
439 assert(sourcePosition->GetDataCount() == vertexCount*3);
440 assert(sourceNormal ->GetDataCount() == vertexCount*3);
442 std::vector<float*> dataTexcoords;
443 for (
size_t i = 0; i < texcoordSources.size(); ++i)
445 dataTexcoords.push_back(texcoordSources[i]->GetData());
454 WritePMD(output, indicesCombined, indicesCombinedCount, dataPosition, dataNormal, dataTexcoords, vertexCount, boneWeights, boneTransforms, propPoints);
474 propPoints.push_back(root);
481 const uint32* indices,
size_t indexCount,
482 const float* position,
const float* normal,
483 const std::vector<float*>& texcoords,
485 const std::vector<VertexBlend>& boneWeights,
const std::vector<BoneTransform>& boneTransforms,
486 const std::vector<PropPoint>& propPoints)
488 static const VertexBlend noBlend = { { 0xFF, 0xFF, 0xFF, 0xFF }, { 0, 0, 0, 0 } };
490 size_t faceCount = indexCount/3;
491 size_t boneCount = boneTransforms.size();
493 assert(boneWeights.size() == vertexCount);
495 size_t propPointsSize = 0;
496 for (
size_t i = 0; i < propPoints.size(); ++i)
498 propPointsSize += 4 + propPoints[i].name.length();
499 propPointsSize += 3*4 + 4*4 + 1;
503 write(output, (uint32)4);
504 write(output, (uint32)(
508 4 + 11*4*vertexCount + 4 + 8*texcoords.size()*vertexCount +
515 write<uint32>(
output, (uint32)vertexCount);
516 write<uint32>(
output, (uint32)texcoords.size());
517 for (
size_t i = 0; i < vertexCount; ++i)
519 output((
char*)&position[i*3], 12);
520 output((
char*)&normal [i*3], 12);
522 for (
size_t s = 0; s < texcoords.size(); ++s)
524 output((
char*)&texcoords[s][i*2], 8);
528 write(output, boneWeights[i]);
530 write(output, noBlend);
534 write(output, (uint32)faceCount);
535 for (
size_t i = 0; i < indexCount; ++i)
537 write(output, (uint16)indices[i]);
541 write(output, (uint32)boneCount);
542 for (
size_t i = 0; i < boneCount; ++i)
544 output((
char*)&boneTransforms[i], 7*4);
548 write(output, (uint32)propPoints.size());
549 for (
size_t i = 0; i < propPoints.size(); ++i)
551 uint32 nameLen = (uint32)propPoints[i].name.length();
552 write(output, nameLen);
553 output(propPoints[i].name.c_str(), nameLen);
554 write(output, propPoints[i].translation);
555 write(output, propPoints[i].orientation);
556 write(output, propPoints[i].bone);
562 REQUIRE(geom->IsMesh(),
"geometry is mesh");
563 FCDGeometryMesh* mesh = geom->GetMesh();
565 if (! mesh->IsTriangles())
566 FCDGeometryPolygonsTools::Triangulate(mesh);
568 REQUIRE(mesh->IsTriangles(),
"mesh is made of triangles");
569 REQUIRE(mesh->GetPolygonsCount() == 1,
"mesh has single set of polygons");
570 FCDGeometryPolygons* polys = mesh->GetPolygons(0);
571 REQUIRE(polys->FindInput(FUDaeGeometryInput::POSITION) != NULL,
"mesh has vertex positions");
572 REQUIRE(polys->FindInput(FUDaeGeometryInput::NORMAL) != NULL,
"mesh has vertex normals");
573 REQUIRE(polys->FindInput(FUDaeGeometryInput::TEXCOORD) != NULL,
"mesh has vertex tex coords");
586 const FMMatrix44& transform,
bool yUp)
588 for (
size_t i = 0; i < vertexCount; ++i)
590 FMVector3 pos (&position[i*3], 0);
591 FMVector3 norm (&normal[i*3], 0);
594 pos = transform.TransformCoordinate(pos);
612 position[i*3] = pos.x;
613 position[i*3+1] = pos.y;
614 position[i*3+2] = pos.z;
616 normal[i*3] = norm.x;
617 normal[i*3+1] = norm.y;
618 normal[i*3+2] = norm.z;
631 std::vector<BoneTransform>& bones, std::vector<PropPoint>& propPoints,
632 const FMMatrix44& transform,
const FMMatrix44& bindTransform,
bool yUp,
bool isXSI)
634 FMMatrix44 scaledTransform;
635 FMMatrix44 scaleMatrix;
646 scaledTransform = bindTransform;
650 for (
size_t i = 0; i < vertexCount; ++i)
652 FMVector3 pos (&position[i*3], 0);
653 FMVector3 norm (&normal[i*3], 0);
656 pos = scaledTransform.TransformCoordinate(pos);
674 position[i*3] = pos.x;
675 position[i*3+1] = pos.y;
676 position[i*3+2] = pos.z;
678 normal[i*3] = norm.x;
679 normal[i*3+1] = norm.y;
680 normal[i*3+2] = norm.z;
686 for (
size_t i = 0; i < propPoints.size(); ++i)
690 propPoints[i].translation[0] = -propPoints[i].translation[0];
691 propPoints[i].orientation[0] = -propPoints[i].orientation[0];
692 propPoints[i].orientation[3] = -propPoints[i].orientation[3];
697 std::swap(propPoints[i].translation[1], propPoints[i].translation[2]);
704 std::swap(propPoints[i].orientation[1], propPoints[i].orientation[2]);
705 propPoints[i].orientation[3] = -propPoints[i].orientation[3];
float weights[maxInfluences]
static void TransformSkinnedModel(float *position, float *normal, size_t vertexCount, std::vector< BoneTransform > &bones, std::vector< PropPoint > &propPoints, const FMMatrix44 &transform, const FMMatrix44 &bindTransform, bool yUp, bool isXSI)
Applies world-space transform to vertex data and transforms Collada's right-handed Y-up / Z-up coordi...
#define REQUIRE(value, message)
Throws a ColladaException unless the value is true.
void SkinReduceInfluences(FCDSkinController *skin, size_t maxInfluenceCount, float minimumWeight)
Like FCDSkinController::ReduceInfluences but works correctly.
static void swap(UniqueRange &p1, UniqueRange &p2)
static void AddDefaultPropPoints(std::vector< PropPoint > &propPoints)
Adds the default "root" prop-point.
FMMatrix44 FMMatrix44_Identity
void ReindexGeometry(FCDGeometryPolygons *polys, FCDSkinController *skin)
void FixSkeletonRoots(FCDControllerInstance &controllerInstance)
Fixes some occasional problems with the skeleton root definitions in a controller.
const Skeleton & FindSkeleton(const FCDControllerInstance &controllerInstance)
Finds the skeleton definition which best matches the given controller.
static void ColladaToPMD(const char *input, OutputCB &output, std::string &xmlErrors)
Converts a COLLADA XML document into the PMD mesh format.
VertexBlend defaultInfluences
const size_t maxInfluences
FMMatrix44 DecomposeToScaleMatrix(const FMMatrix44 &m)
static FCDGeometryPolygons * GetPolysFromGeometry(FCDGeometry *geom)
void TransformBones(std::vector< BoneTransform > &bones, const FMMatrix44 &scaleTransform, bool yUp)
Performs the standard transformations on bones, applying a scale matrix and moving them into the game...
int GetBoneCount() const
Returns the number of bones in the standard-skeleton which this current skeleton is mapped onto...
int GetRealBoneID(const std::string &name) const
Similar to GetBoneID, but only returns a value for the most important (first) nonstandard-skeleton bo...
FCDEntityInstance & GetInstance()
static FMVector3 FMVector3_Normalize(const FMVector3 &vec)
void decomp_affine(HMatrix A, AffineParts *parts)
Wrapper for code shared between the PMD and PSA converters.
void write(OutputCB &output, const T &data)
Outputs a structure, using sizeof to get the size.
static void WritePMD(OutputCB &output, const uint32 *indices, size_t indexCount, const float *position, const float *normal, const std::vector< float * > &texcoords, size_t vertexCount, const std::vector< VertexBlend > &boneWeights, const std::vector< BoneTransform > &boneTransforms, const std::vector< PropPoint > &propPoints)
Writes the model data in the PMD format.
uint8 bones[maxInfluences]
const FMMatrix44 & GetEntityTransform() const
static void AddStaticPropPoints(std::vector< PropPoint > &propPoints, const FMMatrix44 &upAxisTransform, FCDSceneNode *node)
int GetBoneID(const std::string &name) const
Returns the ID number of the standard-skeleton bone, which corresponds to the named nonstandard-skele...
void Log(int severity, const char *msg,...)
static void TransformStaticModel(float *position, float *normal, size_t vertexCount, const FMMatrix44 &transform, bool yUp)
Applies world-space transform to vertex data and transforms Collada's right-handed Y-up / Z-up coordi...