diff --git a/SPT/Export.cpp b/SPT/Export.cpp index e8c2053..81645e2 100644 --- a/SPT/Export.cpp +++ b/SPT/Export.cpp @@ -23,6 +23,27 @@ struct TreeStorage int Lod; }; +inline FbxVector4 CPos(double x, double y, double z) +{ + return FbxVector4(x, -y, z); +} + +inline FbxVector4 CNorm(double x, double y, double z) +{ + return FbxVector4(x, -y, z); +} + +inline FbxVector4 CBiNorm(double x, double y, double z) +{ + return FbxVector4(x, -y, z); +} + +inline FbxVector4 CTang(double x, double y, double z) +{ + return FbxVector4(x, -y, z); +} + + bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) { // SIndexed geometry contains vertices for all LODs. @@ -30,11 +51,10 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) int totalVerticesCount = 0; std::vector uniqueBranchIndices; std::vector uniqueFrondIndices; - { - CSpeedTreeRT::SGeometry geometry; - tree->GetGeometry(geometry); - + CSpeedTreeRT::SGeometry geometry; + tree->GetGeometry(geometry); + { if (geometry.m_sBranches.m_nNumLods > o.Lod && geometry.m_sBranches.m_pNumStrips) { CSpeedTreeRT::SGeometry::SIndexed const *s = &geometry.m_sBranches; @@ -102,9 +122,6 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) // Begin to build the mesh - CSpeedTreeRT::SGeometry geometry; - tree->GetGeometry(geometry); - o.Mesh->InitControlPoints(totalVerticesCount); FbxVector4 *controlPoints = o.Mesh->GetControlPoints(); int offset = 0; @@ -135,52 +152,72 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) int pos = 1; while (pos) { - const char mType = uData[pos]; + const char mType = uData[pos]; pos++; if (!mType || (mType != 'b' && mType != 'f' && mType != 'l')) { break; } - pos++; - int length = uData[pos]; - pos++; - char *nameRaw = (char *)malloc(length + 1); - memcpy(nameRaw, &uData[pos], length); - nameRaw[length] = '\0'; - std::string name(nameRaw); - pos += length; - FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, name.c_str()); + int length = uData[pos]; pos++; + char *name = (char *)malloc(length + 1); + memcpy(name, &uData[pos], length); + name[length] = '\0'; pos += length; switch (mType) { case 'b': - branchMatIdx = o.MeshNode->GetMaterialCount(); + { + std::string finalName = std::string(name) + "_branches"; + FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, finalName.c_str()); + branchMatIdx = o.MeshNode->AddMaterial(m); break; + } case 'f': - frondMatIdx = o.MeshNode->GetMaterialCount(); + { + std::string finalName = std::string(name) + "_fronds"; + FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, finalName.c_str()); + frondMatIdx = o.MeshNode->AddMaterial(m); break; + } case 'l': - leafMatIdx = o.MeshNode->GetMaterialCount(); + { + std::string finalName = std::string(name) + "_leafs"; + FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, finalName.c_str()); + leafMatIdx = o.MeshNode->AddMaterial(m); break; + } default: break; } - o.MeshNode->AddMaterial(m); - free(nameRaw); + free(name); } } FbxLayerElementUV *uvDiffuseLayer = FbxLayerElementUV::Create(o.Mesh, "DiffuseUV"); + FbxLayerElementUV *uvCustom1 = FbxLayerElementUV::Create(o.Mesh, "SizeXY"); + FbxLayerElementUV *uvCustom2 = FbxLayerElementUV::Create(o.Mesh, "CenterXY"); + FbxLayerElementUV *uvCustom3 = FbxLayerElementUV::Create(o.Mesh, "CenterZDimming"); + FbxLayerElementUV *uvCustom4 = FbxLayerElementUV::Create(o.Mesh, "PivotXY"); FbxLayerElementNormal *layerElementNormal = FbxLayerElementNormal::Create(o.Mesh, ""); FbxLayerElementBinormal *layerElementBinormal = FbxLayerElementBinormal::Create(o.Mesh, ""); FbxLayerElementTangent *layerElementTangent = FbxLayerElementTangent::Create(o.Mesh, ""); + FbxLayerElementVertexColor *layerElementColor = FbxLayerElementVertexColor::Create(o.Mesh, ""); uvDiffuseLayer->SetMappingMode(FbxLayerElement::eByControlPoint); uvDiffuseLayer->SetReferenceMode(FbxLayerElement::eDirect); + uvCustom1->SetMappingMode(FbxLayerElement::eByControlPoint); + uvCustom1->SetReferenceMode(FbxLayerElement::eDirect); + uvCustom2->SetMappingMode(FbxLayerElement::eByControlPoint); + uvCustom2->SetReferenceMode(FbxLayerElement::eDirect); + uvCustom3->SetMappingMode(FbxLayerElement::eByControlPoint); + uvCustom3->SetReferenceMode(FbxLayerElement::eDirect); + uvCustom4->SetMappingMode(FbxLayerElement::eByControlPoint); + uvCustom4->SetReferenceMode(FbxLayerElement::eDirect); layerElementNormal->SetMappingMode(FbxLayerElement::eByControlPoint); layerElementNormal->SetReferenceMode(FbxLayerElement::eDirect); layerElementBinormal->SetMappingMode(FbxLayerElement::eByControlPoint); layerElementBinormal->SetReferenceMode(FbxLayerElement::eDirect); layerElementTangent->SetMappingMode(FbxLayerElement::eByControlPoint); layerElementTangent->SetReferenceMode(FbxLayerElement::eDirect); - + layerElementColor->SetMappingMode(FbxLayerElement::eByControlPoint); + layerElementColor->SetReferenceMode(FbxLayerElement::eDirect); // Building branches @@ -196,18 +233,30 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) const float *binorm = &s->m_pBinormals[idx * 3]; const float *tangent = &s->m_pTangents[idx * 3]; const float *uvs = &s->m_pTexCoords[CSpeedTreeRT::TL_DIFFUSE][idx * 2]; - controlPoints[offset + i] = FbxVector4(pos[0], pos[1], pos[2]); - layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2])); - layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2])); - layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2])); + controlPoints[offset + i] = CPos(pos[0], pos[1], pos[2]); + layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2])); + layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2])); + layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2])); uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1])); + uvCustom1->GetDirectArray().Add(FbxVector2(0, 0)); + uvCustom2->GetDirectArray().Add(FbxVector2(0, 0)); + uvCustom3->GetDirectArray().Add(FbxVector2(0, 0)); + uvCustom4->GetDirectArray().Add(FbxVector2(0, 0)); + if (s->m_pColors) + { + unsigned char *colors = (unsigned char *)&s->m_pColors[idx]; + layerElementColor->GetDirectArray().Add(FbxColor((float)colors[0] / 255., (float)colors[1] / 255., (float)colors[2] / 255., (float)colors[3] / 255.)); + } + else + { + layerElementColor->GetDirectArray().Add(FbxColor(0,0,0)); + } } if (branchMatIdx == -1) { FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "BranchMAT"); - branchMatIdx = o.MeshNode->GetMaterialCount(); - o.MeshNode->AddMaterial(m); + branchMatIdx = o.MeshNode->AddMaterial(m); } for(int strip = 0; strip < s->m_pNumStrips[o.Lod]; ++strip) @@ -215,12 +264,12 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) const int length = s->m_pStripLengths[o.Lod][strip]; const int *indices = s->m_pStrips[o.Lod][strip]; - for(int i = 0; i < length - 2; ++i) + for(int i = 0; i < length - 3; ++i) { int polygon[3] = {indices[i], indices[i+1], indices[i+2]}; - if(i % 2) + if (i % 2 == 0) { - std::swap(polygon[2], polygon[1]); + std::swap(polygon[0], polygon[1]); } o.Mesh->BeginPolygon(branchMatIdx, -1, group); @@ -248,18 +297,30 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) const float *binorm = &s->m_pBinormals[idx * 3]; const float *tangent = &s->m_pTangents[idx * 3]; const float *uvs = &s->m_pTexCoords[CSpeedTreeRT::TL_DIFFUSE][idx * 2]; - controlPoints[offset + i] = FbxVector4(pos[0], pos[1], pos[2]); - layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2])); - layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2])); - layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2])); + controlPoints[offset + i] = CPos(pos[0], pos[1], pos[2]); + layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2])); + layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2])); + layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2])); uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1])); + uvCustom1->GetDirectArray().Add(FbxVector2(0, 0)); + uvCustom2->GetDirectArray().Add(FbxVector2(0, 0)); + uvCustom3->GetDirectArray().Add(FbxVector2(0, 0)); + uvCustom4->GetDirectArray().Add(FbxVector2(0, 0)); + if (s->m_pColors) + { + unsigned char *colors = (unsigned char *)&s->m_pColors[idx]; + layerElementColor->GetDirectArray().Add(FbxColor((float)colors[0] / 255., (float)colors[1] / 255., (float)colors[2] / 255., (float)colors[3] / 255.)); + } + else + { + layerElementColor->GetDirectArray().Add(FbxColor(0,0,0)); + } } if (frondMatIdx == -1) { FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "FrondMAT"); - frondMatIdx = o.MeshNode->GetMaterialCount(); - o.MeshNode->AddMaterial(m); + frondMatIdx = o.MeshNode->AddMaterial(m); } for(int strip = 0; strip < s->m_pNumStrips[o.Lod]; ++strip) @@ -270,11 +331,10 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) for(int i = 0; i < length - 2; ++i) { int polygon[3] = {indices[i], indices[i+1], indices[i+2]}; - if(i % 2) + if (i % 2 == 0) { - std::swap(polygon[2], polygon[1]); + std::swap(polygon[0], polygon[1]); } - o.Mesh->BeginPolygon(frondMatIdx, -1, group); for (int j = 0; j < 3; ++j) { @@ -289,7 +349,6 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) // Building leaf cards - bool usesCardLeafs = false; if (tree->GetNumLeafLodLevels() > o.Lod) { bool secondaryIndexForMesh = false; @@ -299,17 +358,18 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) if (leafCount && leafMatIdx == -1) { FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "LeafMAT"); - leafMatIdx = o.MeshNode->GetMaterialCount(); - o.MeshNode->AddMaterial(m); + leafMatIdx = o.MeshNode->AddMaterial(m); } int processedLeafs = 0; for (int leaf = 0; leaf < leafCount; ++leaf) { const CSpeedTreeRT::SGeometry::SLeaf::SCard *card = &s->m_pCards[s->m_pLeafCardIndices[leaf]]; const float *center = &s->m_pCenterCoords[leaf * 3]; + float pivot[2]; + pivot[0] = (card->m_pTexCoords[0 * 2] + card->m_pTexCoords[2 * 2]) / 2.; + pivot[1] = (card->m_pTexCoords[0 * 2 + 1] + card->m_pTexCoords[2 * 2 + 1]) / 2.; if (!card->m_pMesh) { - usesCardLeafs = true; int cornerIndicies[] = {0,0,0,0}; for (int corner = 0; corner < 4; ++corner) { @@ -318,11 +378,26 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) const float *binorm = &s->m_pBinormals[12 * leaf + (corner * 3)]; const float *tangent = &s->m_pTangents[12 * leaf + (corner * 3)]; const float *uvs = &card->m_pTexCoords[corner * 2]; - controlPoints[offset + (processedLeafs * 4 + corner)] = FbxVector4(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]); - layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2])); - layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2])); - layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2])); + controlPoints[offset + (processedLeafs * 4 + corner)] = CPos(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]); + layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2])); + layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2])); + layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2])); uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1])); + uvCustom1->GetDirectArray().Add(FbxVector2(card->m_fWidth, card->m_fHeight)); + uvCustom2->GetDirectArray().Add(FbxVector2(center[0], -center[1])); + uvCustom3->GetDirectArray().Add(FbxVector2(center[2], s->m_pDimming[leaf])); + uvCustom4->GetDirectArray().Add(FbxVector2(pivot[0], pivot[1])); + + if (s->m_pColors) + { + unsigned char *colors = (unsigned char *)&s->m_pColors[leaf * 4 + corner]; + layerElementColor->GetDirectArray().Add(FbxColor((float)colors[0] / 255., (float)colors[1] / 255., (float)colors[2] / 255., (float)colors[3] / 255.)); + } + else + { + layerElementColor->GetDirectArray().Add(FbxColor(0,0,0)); + } + cornerIndicies[corner] = offset + (processedLeafs * 4 + corner); } @@ -353,27 +428,26 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) if (leafCount && leafMatIdx == -1) { FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, "LeafMAT"); - leafMatIdx = o.MeshNode->GetMaterialCount(); - o.MeshNode->AddMaterial(m); + leafMatIdx = o.MeshNode->AddMaterial(m); } for (int leaf = 0; leaf < leafCount; ++leaf) { const CSpeedTreeRT::SGeometry::SLeaf::SCard *card = &s->m_pCards[s->m_pLeafCardIndices[leaf]]; const float *center = &s->m_pCenterCoords[leaf * 3]; + const float *pivot = card->m_afPivotPoint; if (card->m_pMesh) { - if (usesCardLeafs && leafMatIdx2 == -1) + if (leafMatIdx2 == -1) { const char *leafMatName = o.MeshNode->GetMaterial(leafMatIdx)->GetName(); std::string newMatName("LeafMeshMAT"); if (leafMatName && leafMatName != "LeafMAT") { - newMatName = std::string(leafMatName) + "_lMesh"; + newMatName = std::string(leafMatName) + "mesh"; } FbxSurfaceMaterial *m = FbxSurfaceLambert::Create(o.Scene, newMatName.c_str()); - leafMatIdx2 = o.MeshNode->GetMaterialCount(); - o.MeshNode->AddMaterial(m); + leafMatIdx2 = o.MeshNode->AddMaterial(m); } else if (leafMatIdx2 == -1) { @@ -387,18 +461,24 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) const float *binorm = &mesh->m_pBinormals[vert * 3]; const float *tangent = &mesh->m_pTangents[vert * 3]; const float *uvs = &mesh->m_pTexCoords[vert * 2]; - controlPoints[offset + vert] = FbxVector4(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]); - layerElementNormal->GetDirectArray().Add(FbxVector4(normal[0], normal[1], normal[2])); - layerElementBinormal->GetDirectArray().Add(FbxVector4(binorm[0], binorm[1], binorm[2])); - layerElementTangent->GetDirectArray().Add(FbxVector4(tangent[0], tangent[1], tangent[2])); + controlPoints[offset + vert] = CPos(pos[0] + center[0], pos[1] + center[1], pos[2] + center[2]); + layerElementNormal->GetDirectArray().Add(CNorm(normal[0], normal[1], normal[2])); + layerElementBinormal->GetDirectArray().Add(CBiNorm(binorm[0], binorm[1], binorm[2])); + layerElementTangent->GetDirectArray().Add(CTang(tangent[0], tangent[1], tangent[2])); + layerElementColor->GetDirectArray().Add(FbxColor(0,0,0)); uvDiffuseLayer->GetDirectArray().Add(FbxVector2(uvs[0], uvs[1])); + uvCustom1->GetDirectArray().Add(FbxVector2(card->m_fWidth, card->m_fHeight)); + uvCustom2->GetDirectArray().Add(FbxVector2(center[0], center[1])); + uvCustom3->GetDirectArray().Add(FbxVector2(center[2], s->m_pDimming[leaf])); + uvCustom4->GetDirectArray().Add(FbxVector2(pivot[0], pivot[1])); } for (int i = 0; i < mesh->m_nNumIndices - 2; i+=3) { + int polygon[3] = {mesh->m_pIndices[i+1], mesh->m_pIndices[i], mesh->m_pIndices[i+2]}; o.Mesh->BeginPolygon(leafMatIdx2, -1, group); for (int j = 0; j < 3; ++j) { - o.Mesh->AddPolygon(offset + mesh->m_pIndices[i + j]); + o.Mesh->AddPolygon(offset + polygon[j]); } o.Mesh->EndPolygon(); } @@ -411,7 +491,13 @@ bool GenerateTree(CSpeedTreeRT *tree, TreeStorage &o) layer->SetNormals(layerElementNormal); layer->SetBinormals(layerElementBinormal); layer->SetTangents(layerElementTangent); + layer->SetVertexColors(layerElementColor); layer->SetUVs(uvDiffuseLayer, FbxLayerElement::eTextureDiffuse); + layer->SetUVs(uvCustom1, FbxLayerElement::eTextureEmissive); // cardWidth, cardHeight + layer->SetUVs(uvCustom2, FbxLayerElement::eTextureAmbient); // leafPositionX, leafPositionY + layer->SetUVs(uvCustom3, FbxLayerElement::eTextureSpecular); // leafPositionZ, leafDimming + layer->SetUVs(uvCustom4, FbxLayerElement::eTextureNormalMap); // cardPivotU, cardPivotV + return true; } diff --git a/SPT/SPT.cpp b/SPT/SPT.cpp index 0cc36c1..8973556 100644 --- a/SPT/SPT.cpp +++ b/SPT/SPT.cpp @@ -63,14 +63,14 @@ bool ProcessTree(std::wstring const &sptFilePath) FILE *f = NULL; if (_wfopen_s(&f, sptFilePath.c_str(), L"rb")) { - std::wcerr << "Failed to open: " << sptFilePath << std::endl; + std::cerr << "Failed to open: " << w2a(sptFilePath).c_str() << std::endl; return false; } fseek(f, 0, SEEK_END); long size = ftell(f); if (!size) { - std::wcerr << "File corrupted: " << sptFilePath << std::endl; + std::cerr << "File corrupted: " << w2a(sptFilePath).c_str() << std::endl; fclose(f); return false; } @@ -81,6 +81,7 @@ bool ProcessTree(std::wstring const &sptFilePath) CSpeedTreeRT *tree = new CSpeedTreeRT; if (!tree->LoadTree(buf, static_cast(size))) { + std::cerr << "Couldn't load the tree: " << w2a(sptFilePath).c_str() << std::endl; free(buf); delete tree; } @@ -89,7 +90,9 @@ bool ProcessTree(std::wstring const &sptFilePath) tree->SetBranchLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC); tree->SetLeafLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC); tree->SetFrondLightingMethod(CSpeedTreeRT::LIGHT_DYNAMIC); + tree->Compute(0, tree->GetSeed()); + ExportTree(tree, sptFilePath); free(buf); diff --git a/SPT/SPT.suo b/SPT/SPT.suo deleted file mode 100644 index c6007bd..0000000 Binary files a/SPT/SPT.suo and /dev/null differ