diff --git a/ldae_exporter.cpp b/ldae_exporter.cpp new file mode 100644 index 0000000..299bb5c --- /dev/null +++ b/ldae_exporter.cpp @@ -0,0 +1,447 @@ +#include "ldae_exporter.h" +#include "scene/main/node.h" +#include "scene/3d/light.h" +#include "ldebug.h" +#include "lportal.h" + +#define FSL(a) m_File.store_line(a) +#define FSS(a) m_File.store_string(a) + +#define FSL_T(a, b) {for (int n=0; n"); + for (int n=0; n"); + + // mesh instances + FSL("\t"); + + // merged mesh? + if (m_pMergedMI) + SaveData_MeshInstance(*m_pMergedMI); + + for (int n=0; n"); + + m_Stage = ST_SCENE_GRAPH; + Save_Mid(); + + // now save the scene graph + SaveScene_Recursive(pNode, 0); + + Save_Final(); + + m_File.close(); + return true; +} + + +bool LDAEExporter::Save_Preamble() +{ + FSL(""); + FSL(""); + + return true; +} + +bool LDAEExporter::Save_Mid() +{ + FSL("\t"); + FSL("\t\t"); + + if (m_bAddRootNode) + { + FSL_T(3, ""); + + // rotate x by 90 degrees + FSL_T(3, "1 0 0 0 0 0 -1 0 0 1 0 0 0 0 0 1"); + } + + if (m_pMergedMI) + { + String sz = SaveScene_MeshInstance(*m_pMergedMI, 3); + FSL(sz); // merged node close + + FSL_T(3, ""); + } + + return true; +} + +void LDAEExporter::TransformToMatrix(const Transform &tr, float * m) +{ + const Basis &b = tr.basis; + + m[0] = b.elements[0][0]; + m[1] = b.elements[0][1]; + m[2] = b.elements[0][2]; + m[3] = tr.origin.x; + + m[4] = b.elements[1][0]; + m[5] = b.elements[1][1]; + m[6] = b.elements[1][2]; + m[7] = tr.origin.y; + + m[8] = b.elements[2][0]; + m[9] = b.elements[2][1]; + m[10] = b.elements[2][2]; + m[11] = tr.origin.z; + + m[12] = 0.0f; + m[13] = 0.0f; + m[14] = 0.0f; + m[15] = 1.0f; +} + +String LDAEExporter::SaveScene_Light(const Light &l, int depth) +{ + int tab_depth = 3 + depth; + + String name = l.get_name(); + String long_name = name + "-light"; + FSL_T(tab_depth, ""); + + WriteMatrix(l.get_transform(), tab_depth+1); + + FSL_T(tab_depth+1, ""); + + String sz = ""; + for (int n=0; n"); + + for (int n=0; n<16; n++) + { + FSS(ftos(mat[n]) + " "); + } + + FSS("\n"); +} + + +String LDAEExporter::SaveScene_MeshInstance(const MeshInstance &mi, int depth) +{ + int tab_depth = 3 + depth; + + String name = mi.get_name(); + String long_name = name + "-mesh"; + FSL_T(tab_depth, ""); + + + WriteMatrix(mi.get_transform(), tab_depth+1); + + FSL_T(tab_depth+1, ""); + FSL_T(tab_depth+1, ""); + + String sz = ""; + for (int n=0; n"); + + return sz; +} + +String LDAEExporter::SaveScene_Spatial(const Spatial &sp, int depth) +{ + int tab_depth = 3 + depth; + String name = sp.get_name(); + + FSL_T(tab_depth, ""); + + WriteMatrix(sp.get_transform(), tab_depth+1); + + String sz = ""; + for (int n=0; n"); // level + } + + if (m_bAddRootNode) + { + FSL_T(3, ""); // root + } + + FSL("\t\t"); + FSL("\t"); + FSL("\t"); + FSL("\t\t"); + FSL("\t"); + + + FSL(""); + return true; +} + + +bool LDAEExporter::IsPortal(const MeshInstance &mi) +{ + if (LPortal::NameStartsWith(&mi, "portal_")) + return true; + + return false; +} + + +bool LDAEExporter::SaveScene_Recursive(Node * pNode, int depth) +{ + String szClose = ""; + + // mesh instance? + MeshInstance * pMI = Object::cast_to(pNode); + if (pMI) + { + if (m_bRemovePortals && (IsPortal(*pMI))) + { + // portal .. not exporting + } + else + { + if (m_Stage == ST_DATA) + m_MeshInstances.push_back(pMI); + else + szClose = SaveScene_MeshInstance(*pMI, depth); + } + } + + // light? + Light * pLight = Object::cast_to(pNode); + if (pLight) + { + if (m_Stage == ST_DATA) + m_Lights.push_back(pLight); + else + szClose = SaveScene_Light(*pLight, depth); + } + + // spatial? (and only a spatial) + if (pNode->get_class() == "Spatial") + { + if (m_Stage == ST_SCENE_GRAPH) + { + szClose = SaveScene_Spatial(*Object::cast_to(pNode), depth); + } + } + + + // go through the children + for (int n=0; nget_child_count(); n++) + { + SaveScene_Recursive(pNode->get_child(n), depth+1); + } + + // a closing xml expression + if (szClose != "") + { + FSL(szClose); + } + + return true; +} + + + + +bool LDAEExporter::SaveData_Light(const Light &light) +{ + String name = light.get_name(); + String long_name = name + "-light"; + + int t = 1; + + String szLightType = "point"; + //if (light.is_class("OmniLight") + + if (light.is_class("SpotLight")) + szLightType = "spot"; + + if (light.is_class("DirectionalLight")) + szLightType = "directional"; + + FSL_T(t, ""); + FSL_T(t+1, ""); + FSL_T(t+2, "<" + szLightType + ">"); + + + + FSL_T(t+2, ""); + FSL_T(t+1, ""); + FSL_T(t, ""); + + return true; +} + +//static bool g_SingleDAETest = false; + + +bool LDAEExporter::SaveData_MeshInstance(const MeshInstance &mi) +{ +// if (g_SingleDAETest) +// return true; +// g_SingleDAETest = true; + + Ref rmesh = mi.get_mesh(); + Array arrays = rmesh->surface_get_arrays(0); + PoolVector verts = arrays[VS::ARRAY_VERTEX]; + PoolVector norms = arrays[VS::ARRAY_NORMAL]; + PoolVector uv1s = arrays[VS::ARRAY_TEX_UV]; + PoolVector inds = arrays[VS::ARRAY_INDEX]; + + int nVerts = verts.size(); + int nInds = inds.size(); + int nFaces = nInds / 3; + + String name = mi.get_name(); + String long_name = name + "-mesh"; + + + FSL("\t"); + FSL("\t\t"); + + // positions + FSL("\t\t\t"); + + FSS("\t\t\t\t"); + for (int n=0; n\n"); + + FSL("\t\t\t\t"); + FSL("\t\t\t\t\t"); + FSL("\t\t\t\t\t\t"); + FSL("\t\t\t\t\t\t"); + FSL("\t\t\t\t\t\t"); + + FSL("\t\t\t\t\t"); + FSL("\t\t\t\t"); + + FSL("\t\t\t"); + + // normals + if (norms.size()) + { + FSL("\t\t\t"); + + FSS("\t\t\t\t"); + for (int n=0; n\n"); + + FSL("\t\t\t\t"); + FSL("\t\t\t\t\t"); + FSL("\t\t\t\t\t\t"); + FSL("\t\t\t\t\t\t"); + FSL("\t\t\t\t\t\t"); + + FSL("\t\t\t\t\t"); + FSL("\t\t\t\t"); + + FSL("\t\t\t"); + } + + FSL("\t\t\t"); + FSL("\t\t\t\t"); + FSL("\t\t\t"); + + FSL("\t\t\t"); + FSL("\t\t\t\t"); + if (norms.size()) + { + FSL("\t\t\t\t"); + } + + FSS("\t\t\t\t

"); + + // DAE has face winding reversed compared to godot + for (int f=0; f\n"); + + FSL("\t\t\t"); + + FSL("\t\t"); + FSL("\t"); + return true; +} + + +#undef FSL +#undef FSS + diff --git a/ldae_exporter.h b/ldae_exporter.h new file mode 100644 index 0000000..41a289d --- /dev/null +++ b/ldae_exporter.h @@ -0,0 +1,59 @@ +#pragma once + +#include "core/bind/core_bind.h" +#include "scene/3d/mesh_instance.h" + +class Light; + +class LDAEExporter +{ + enum eStage + { + ST_DATA, + ST_SCENE_GRAPH, + }; + +public: + LDAEExporter(); + bool SaveScene(Node * pNode, String szFilename, bool bRemovePortals = false); + void SetMergedMeshInstance(MeshInstance * pMI) {m_pMergedMI = pMI;} + + +private: + + bool SaveScene_Recursive(Node * pNode, int depth); + + + + String SaveScene_MeshInstance(const MeshInstance &mi, int depth); + String SaveScene_Light(const Light &l, int depth); + String SaveScene_Spatial(const Spatial &sp, int depth); + + bool SaveData_Light(const Light &light); + bool SaveData_MeshInstance(const MeshInstance &mi); + + + bool Save_Preamble(); + bool Save_Mid(); + bool Save_Final(); + + void WriteMatrix(const Transform &tr, int tab_depth); + void TransformToMatrix(const Transform &tr, float * m); + + bool IsPortal(const MeshInstance &mi); + + Vector m_MeshInstances; + Vector m_Lights; + + _File m_File; + eStage m_Stage; + + // export the DAE with everything under a root node .. this is sometimes more convenient + bool m_bAddRootNode; + + // remove portals + bool m_bRemovePortals; + + // if we are exporting the level with a merged mesh too + MeshInstance * m_pMergedMI; +}; diff --git a/lhelper.cpp b/lhelper.cpp index f9168ed..609e654 100644 --- a/lhelper.cpp +++ b/lhelper.cpp @@ -7,6 +7,11 @@ // for ::free #include +LHelper::LHelper() +{ + SetUnMergeParams(0.1f, 0.95f); +} + String LHelper::LFace::ToString() const { @@ -18,7 +23,7 @@ String LHelper::LFace::ToString() const sz += ", "; } - sz += " norm : "; + sz += "norm : "; for (int c=0; c<3; c++) { sz += String(Variant(m_Norm[c])); @@ -97,8 +102,15 @@ bool LHelper::FillMergedFromMesh(LMerged &merged, const MeshInstance &mesh) if (merged.m_UV2s.size() == 0) { - LWARN(5, "Merged mesh has no secondary UVs"); - return false; + LPRINT(5, "Merged mesh has no secondary UVs, using primary UVs"); + + merged.m_UV2s = arrays[VS::ARRAY_TEX_UV]; + + if (merged.m_UV2s.size() == 0) + { + LWARN(5, "Merged mesh has no UVs"); + return false; + } } int miCount = 0; @@ -120,6 +132,13 @@ bool LHelper::FillMergedFromMesh(LMerged &merged, const MeshInstance &mesh) } +void LHelper::SetUnMergeParams(float thresh_dist, float thresh_dot) +{ + m_MergeParams.m_fThresholdDist = thresh_dist; + m_MergeParams.m_fThresholdDist_Squared = thresh_dist * thresh_dist; + m_MergeParams.m_fThresholdDot = thresh_dot; +} + // take the UV2 coords from the merged mesh and attach these to the SOB meshes bool LHelper::UnMergeSOBs(LRoomManager &manager, MeshInstance * pMerged) { @@ -134,8 +153,13 @@ bool LHelper::UnMergeSOBs(LRoomManager &manager, MeshInstance * pMerged) return false; // go through each sob mesh +// for (int n=1; n<2; n++) for (int n=0; n &uvs, const V return -1; } -bool LHelper::DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1) const +bool LHelper::DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1, bool bDebug) const { - return DoPosNormsApproxMatch(sob_f.m_Pos[c0], sob_f.m_Norm[c0], m_face.m_Pos[c1], m_face.m_Norm[c1]); + return DoPosNormsApproxMatch(sob_f.m_Pos[c0], sob_f.m_Norm[c0], m_face.m_Pos[c1], m_face.m_Norm[c1], bDebug); } -bool LHelper::DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm) const +bool LHelper::DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm, bool bDebug) const { + bDebug = false; + + float thresh_diff = m_MergeParams.m_fThresholdDist; + float thresh_diff_squared = m_MergeParams.m_fThresholdDist_Squared; + float x_diff = fabs (b_pos.x - a_pos.x); - if (x_diff > 0.2f) + if (x_diff > thresh_diff) + { +#ifdef LDEBUG_UNMERGE + if (bDebug) + LPRINT(5, "\t\t\t\tRejecting x_diff " + ftos(x_diff)); +#endif return false; + } + + float z_diff = fabs (b_pos.z - a_pos.z); + if (z_diff > thresh_diff) + { +#ifdef LDEBUG_UNMERGE + if (bDebug) + LPRINT(5, "\t\t\t\tRejecting z_diff " + ftos(z_diff)); +#endif + return false; + } + + float y_diff = fabs (b_pos.y - a_pos.y); + if (y_diff > thresh_diff) + { +#ifdef LDEBUG_UNMERGE + if (bDebug) + LPRINT(5, "\t\t\t\tRejecting y_diff " + ftos(y_diff)); +#endif + return false; + } + Vector3 pos_diff = b_pos - a_pos; - if (pos_diff.length_squared() > 0.1f) + if (pos_diff.length_squared() > thresh_diff_squared) // 0.1 + { +#ifdef LDEBUG_UNMERGE + if (bDebug) + LPRINT(5, "\t\t\t\tRejecting length squared " + ftos(pos_diff.length_squared())); +#endif + return false; + } // make sure both are normalized Vector3 na = a_norm;//.normalized(); Vector3 nb = b_norm;//.normalized(); float norm_dot = na.dot(nb); - if (norm_dot < 0.95f) + if (norm_dot < m_MergeParams.m_fThresholdDot) + { +#ifdef LDEBUG_UNMERGE + if (bDebug) + LPRINT(5, "\t\t\t\tRejecting normal " + ftos(norm_dot) + " na : " + String(na) + ", nb : " + String(nb)); +#endif return false; + } return true; } +int LHelper::DoFacesMatch_Offset(const LFace& sob_f, const LFace &m_face, int offset) const +{ +#ifdef LDEBUG_UNMERGE + // debug + String sz = "\t\tPOSS match sob : "; + sz += sob_f.ToString(); + sz += "\n\t\t\tmerged : "; + sz += m_face.ToString(); + LPRINT(2, sz); +#endif + + + // does 2nd and third match? + int offset1 = (offset + 1) % 3; + if (!DoFaceVertsApproxMatch(sob_f, m_face, 1, offset1, true)) + return -1; + + int offset2 = (offset + 2) % 3; + if (!DoFaceVertsApproxMatch(sob_f, m_face, 2, offset2, true)) + return -1; + + return offset; +} + + // -1 for no match, or 0 for 0 offset match, 1 for +1, 2 for +2 offset match... int LHelper::DoFacesMatch(const LFace& sob_f, const LFace &m_face) const { // match one - int offset = 0; - bool bMatch = false; - for (offset = 0; offset < 3; offset++) + for (int offset = 0; offset < 3; offset++) { - if (DoFaceVertsApproxMatch(sob_f, m_face, 0, offset)) + if (DoFaceVertsApproxMatch(sob_f, m_face, 0, offset, false)) { - bMatch = true; - break; + int res = DoFacesMatch_Offset(sob_f, m_face, offset); + + if (res != -1) + return res; } } - // none found that match, most common scenario - if (!bMatch) - return -1; - - // debug -// String sz = "\t\tposs match sob : "; -// sz += sob_f.ToString(); -// sz += " merged : "; -// sz += m_face.ToString(); -// LPRINT(2, sz); - - - // does 2nd and third match? - int offset1 = (offset + 1) % 3; - if (!DoFaceVertsApproxMatch(sob_f, m_face, 1, offset1)) - return -1; - - int offset2 = (offset + 2) % 3; - if (!DoFaceVertsApproxMatch(sob_f, m_face, 2, offset2)) - return -1; - - return offset; + return -1; // no match } @@ -318,6 +391,10 @@ bool LHelper::UnMerge_SOB(MeshInstance &mi, LMerged &merged) lf.m_index[c] = ind; } +#ifdef LDEBUG_UNMERGE + LPRINT(5, "lface : " + lf.ToString()); +#endif + // find matching face // int miCount = 0; bool bMatchFound = false; @@ -533,7 +610,7 @@ finish: } -bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged) +bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged, bool bLightmapUnwrap) { PoolVector verts; PoolVector normals; @@ -554,12 +631,12 @@ bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged) continue; // to get the transform, the node has to be in the tree, so temporarily show if hidden - bool bShowing = sob.m_bShow; - sob.Show(true); + //bool bShowing = sob.m_bShow; + //sob.Show(true); Merge_MI(*pMI, verts, normals, inds); - sob.Show(bShowing); + //sob.Show(bShowing); } @@ -608,7 +685,8 @@ bool LHelper::MergeSOBs(LRoomManager &manager, MeshInstance * pMerged) am->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, Array(), Mesh::ARRAY_COMPRESS_DEFAULT); - LightmapUnwrap(am, pMerged->get_global_transform()); + if (bLightmapUnwrap) + LightmapUnwrap(am, pMerged->get_global_transform()); // duplicate the UV2 to uv1 just in case they are needed arr[Mesh::ARRAY_TEX_UV] = arr[Mesh::ARRAY_TEX_UV2]; diff --git a/lhelper.h b/lhelper.h index 4ae7b87..6b34b12 100644 --- a/lhelper.h +++ b/lhelper.h @@ -5,6 +5,8 @@ class LHelper { public: + LHelper(); + struct LFace { Vector3 m_Pos[3]; @@ -43,11 +45,13 @@ public: MeshInstance * CreateLightmapProxy(LRoomManager &manager); // for lightmapping - bool MergeSOBs(LRoomManager &manager, MeshInstance * pMerged); + bool MergeSOBs(LRoomManager &manager, MeshInstance * pMerged, bool bLightmapUnwrap = true); // take the UV2 coords from the merged mesh and attach these to the SOB meshes bool UnMergeSOBs(LRoomManager &manager, MeshInstance * pMerged); + void SetUnMergeParams(float thresh_dist, float thresh_dot); + // bool UnMergeSOBs(LRoomManager &manager, const PoolVector &uv2s); // main function for getting merged uv2 back to sobs @@ -71,8 +75,10 @@ private: void Transform_Norms(const PoolVector &normsLocal, PoolVector &normsWorld, const Transform &tr) const; int DoFacesMatch(const LFace& sob_f, const LFace &m_face) const; - bool DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1) const; - bool DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm) const; + int DoFacesMatch_Offset(const LFace& sob_f, const LFace &m_face, int offset) const; + + bool DoFaceVertsApproxMatch(const LFace& sob_f, const LFace &m_face, int c0, int c1, bool bDebug) const; + bool DoPosNormsApproxMatch(const Vector3 &a_pos, const Vector3 &a_norm, const Vector3 &b_pos, const Vector3 &b_norm, bool bDebug) const; int FindOrAddVert(LVector &uni_verts, const LVert &vert) const; @@ -80,4 +86,15 @@ private: bool FillMergedFromMesh(LMerged &merged, const MeshInstance &mesh); // bool xatlas_mesh_lightmap_unwrap(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y); + + + // internal data + // merging params + struct LMergeParams + { + float m_fThresholdDist; + float m_fThresholdDist_Squared; + float m_fThresholdDot; + } m_MergeParams; + }; diff --git a/lportal.cpp b/lportal.cpp index a4f1a8f..a276bf4 100644 --- a/lportal.cpp +++ b/lportal.cpp @@ -26,7 +26,7 @@ ///////////////////////////////////////////////////////////////////// -bool LPortal::NameStartsWith(Node * pNode, String szSearch) +bool LPortal::NameStartsWith(const Node * pNode, String szSearch) { int sl = szSearch.length(); diff --git a/lportal.h b/lportal.h index 79959a5..3b7b929 100644 --- a/lportal.h +++ b/lportal.h @@ -82,7 +82,7 @@ public: void ReverseWindingOrder(); // useful funcs - static bool NameStartsWith(Node * pNode, String szSearch); + static bool NameStartsWith(const Node * pNode, String szSearch); static String FindNameAfter(Node * pNode, String szStart); private: diff --git a/lportal_all.cpp b/lportal_all.cpp index fad7815..da2f78a 100644 --- a/lportal_all.cpp +++ b/lportal_all.cpp @@ -5,6 +5,8 @@ #define LDEBUG_LIGHTS #define LDEBUG_LIGHT_AFFECTED_ROOMS +//#define LDEBUG_UNMERGE + // single compilation unit #include "register_types.cpp" #include "ldebug.cpp" @@ -21,4 +23,5 @@ #include "ltrace.cpp" #include "lmain_camera.cpp" #include "larea.cpp" +#include "ldae_exporter.cpp" diff --git a/lroom_manager.cpp b/lroom_manager.cpp index d064dcf..500327b 100644 --- a/lroom_manager.cpp +++ b/lroom_manager.cpp @@ -30,6 +30,7 @@ #include "lroom.h" #include "lhelper.h" #include "lscene_saver.h" +#include "ldae_exporter.h" #define LROOMLIST m_pRoomList #define CHECK_ROOM_LIST if (!CheckRoomList())\ @@ -68,6 +69,15 @@ LRoomManager::LRoomManager() m_pRoomList = 0; + + + // loses detail at approx .. 0.00001 + // dot 0.9999 + // however, this will depend on the map so we will use some more approximate figures, and allow + // the user to change in rare cases where this fails + m_fLightmapUnMerge_ThresholdDist = 0.001f; + m_fLightmapUnMerge_ThresholdDot = 0.99f; + if (!Engine::get_singleton()->is_editor_hint()) { CreateDebug(); @@ -1233,25 +1243,65 @@ bool LRoomManager::rooms_transfer_uv2s(Node * pMeshInstance_From, Node * pMeshIn } -bool LRoomManager::rooms_unmerge_sobs(Node * pMergeMeshInstance) +bool LRoomManager::rooms_unmerge_sobs(Node * pMergeMeshInstance, float thresh_dist, float thresh_dot) { MeshInstance * pMI = Object::cast_to(pMergeMeshInstance); LHelper helper; + helper.SetUnMergeParams(thresh_dist, thresh_dot); Lawn::LDebug::m_bRunning = false; bool res = helper.UnMergeSOBs(*this, pMI); Lawn::LDebug::m_bRunning = true; return res; } +bool LRoomManager::export_scene_DAE(Node * pNode, String szFilename) +{ + LDAEExporter dae; + return dae.SaveScene(pNode, szFilename); +} + bool LRoomManager::rooms_save_scene(Node * pNode, String szFilename) { LSceneSaver saver; return saver.SaveScene(pNode, szFilename); } +void LRoomManager::lightmap_set_unmerge_params(float thresh_dist, float thresh_dot) +{ + // sanitize? NYI + m_fLightmapUnMerge_ThresholdDist = thresh_dist; + m_fLightmapUnMerge_ThresholdDot = thresh_dot; +} -MeshInstance * LRoomManager::rooms_convert_lightmap_internal(String szProxyFilename, String szLevelFilename) +bool LRoomManager::lightmap_external_unmerge(Node * pMergeMeshInstance, String szLevelFilename) +{ + ResolveRoomListPath(); + if (!CheckRoomList()) + { + WARN_PRINT_ONCE("rooms_convert_lightmap_external : rooms not set"); + return 0; + } + + LRoomConverter conv; + conv.Convert(*this, true, true, false); + + bool res = rooms_unmerge_sobs(pMergeMeshInstance, m_fLightmapUnMerge_ThresholdDist, m_fLightmapUnMerge_ThresholdDot); + + if (res) + { + // save the UV2 mapped level + if (szLevelFilename != "") + rooms_save_scene(LROOMLIST, szLevelFilename); + + return true; + } + + return false; +} + + +MeshInstance * LRoomManager::lightmap_internal(String szProxyFilename, String szLevelFilename) { ResolveRoomListPath(); if (!CheckRoomList()) @@ -1264,6 +1314,10 @@ MeshInstance * LRoomManager::rooms_convert_lightmap_internal(String szProxyFilen conv.Convert(*this, true, true, false); LHelper helper; + + // as we are doing an unmerge, we want to allow the user to override the parameters of the unmerge + helper.SetUnMergeParams(m_fLightmapUnMerge_ThresholdDist, m_fLightmapUnMerge_ThresholdDot); + Lawn::LDebug::m_bRunning = false; MeshInstance * pMI = helper.CreateLightmapProxy(*this); @@ -1283,15 +1337,70 @@ MeshInstance * LRoomManager::rooms_convert_lightmap_internal(String szProxyFilen return pMI; } +bool LRoomManager::lightmap_external_export(String szFilename) // DAE filename +{ + ResolveRoomListPath(); + CHECK_ROOM_LIST + + LRoomConverter conv; + conv.Convert(*this, true, true, false, true); + +// LRoomConverter conv; +// conv.Convert(*this, true, true, false); + +//#m_Manager.rooms_single_room_convert(true, false) +// rooms_single_room_convert( + + + +// if (!m_pRoomList) +// return false; + + rooms_set_active(false); + + // first create a temporary mesh instance + MeshInstance * pMerged = memnew(MeshInstance); + pMerged->set_name("Merged"); + add_child(pMerged); + + + LHelper helper; + Lawn::LDebug::m_bRunning = false; + bool res = helper.MergeSOBs(*this, pMerged, false); + Lawn::LDebug::m_bRunning = true; + + // create the merged geometry + if (res) + { + // save as a DAE + LDAEExporter dae; + dae.SetMergedMeshInstance(pMerged); + + res = dae.SaveScene(m_pRoomList, szFilename, true); + } + + pMerged->queue_delete(); + + rooms_set_active(true); + return res; +} bool LRoomManager::rooms_merge_sobs(Node * pMergeMeshInstance) { MeshInstance * pMI = Object::cast_to(pMergeMeshInstance); + + // first make sure all SOBs are showing by deactivating LPortal + rooms_set_active(false); + LHelper helper; Lawn::LDebug::m_bRunning = false; bool res = helper.MergeSOBs(*this, pMI); Lawn::LDebug::m_bRunning = true; + + // finally reactivate LPortal + rooms_set_active(true); + return res; } @@ -1881,10 +1990,17 @@ void LRoomManager::_bind_methods() ClassDB::bind_method(D_METHOD("rooms_save_scene", "node", "filename"), &LRoomManager::rooms_save_scene); // stuff for external workflow .. works but don't expose yet -// ClassDB::bind_method(D_METHOD("rooms_merge_sobs"), &LRoomManager::rooms_merge_sobs); -// ClassDB::bind_method(D_METHOD("rooms_unmerge_sobs"), &LRoomManager::rooms_unmerge_sobs); -// ClassDB::bind_method(D_METHOD("rooms_transfer_uv2s"), &LRoomManager::rooms_transfer_uv2s); + //ClassDB::bind_method(D_METHOD("rooms_merge_sobs"), &LRoomManager::rooms_merge_sobs); + //ClassDB::bind_method(D_METHOD("rooms_unmerge_sobs"), &LRoomManager::rooms_unmerge_sobs); + //ClassDB::bind_method(D_METHOD("rooms_transfer_uv2s"), &LRoomManager::rooms_transfer_uv2s); + ClassDB::bind_method(D_METHOD("lightmap_external_export", "DAE filename"), &LRoomManager::lightmap_external_export); + ClassDB::bind_method(D_METHOD("lightmap_external_unmerge", "merged mesh instance", "output level filename"), &LRoomManager::lightmap_external_unmerge); + ClassDB::bind_method(D_METHOD("lightmap_set_unmerge_params", "threshold distance (e.g. 0.001)", "threshold dot (e.g. 0.99)"), &LRoomManager::lightmap_set_unmerge_params); + + + // lightmapping + ClassDB::bind_method(D_METHOD("lightmap_internal", "output proxy filename", "output level filename"), &LRoomManager::lightmap_internal); // debugging ClassDB::bind_method(D_METHOD("rooms_set_logging", "level 0 to 6"), &LRoomManager::rooms_set_logging); @@ -1899,8 +2015,6 @@ void LRoomManager::_bind_methods() ClassDB::bind_method(D_METHOD("rooms_set_debug_frame_string", "active"), &LRoomManager::rooms_set_debug_frame_string); ClassDB::bind_method(D_METHOD("rooms_get_debug_frame_string"), &LRoomManager::rooms_get_debug_frame_string); - // lightmapping - ClassDB::bind_method(D_METHOD("rooms_convert_lightmap_internal", "proxy filename", "level filename"), &LRoomManager::rooms_convert_lightmap_internal); // functions to add dynamic objects to the culling system // Note that these should not be placed directly in rooms, the system will 'soft link' to them @@ -1934,6 +2048,9 @@ void LRoomManager::_bind_methods() ClassDB::bind_method(D_METHOD("set_rooms_path", "rooms"), &LRoomManager::set_rooms_path); ClassDB::bind_method(D_METHOD("get_rooms_path"), &LRoomManager::get_rooms_path); + ClassDB::bind_method(D_METHOD("export_scene_DAE", "node", "filename"), &LRoomManager::export_scene_DAE); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "rooms"), "set_rooms_path", "get_rooms_path"); } diff --git a/lroom_manager.h b/lroom_manager.h index d23d433..3243d1f 100644 --- a/lroom_manager.h +++ b/lroom_manager.h @@ -106,12 +106,16 @@ public: // LIGHTMAPS // helper function to merge SOB meshes for producing lightmaps VIA external blender workflow bool rooms_merge_sobs(Node * pMergeMeshInstance); - bool rooms_unmerge_sobs(Node * pMergeMeshInstance); + bool rooms_unmerge_sobs(Node * pMergeMeshInstance, float thresh_dist, float thresh_dot); bool rooms_transfer_uv2s(Node * pMeshInstance_From, Node * pMeshInstance_To); + bool lightmap_external_export(String szFilename); // DAE filename + bool lightmap_external_unmerge(Node * pMergeMeshInstance, String szLevelFilename); + void lightmap_set_unmerge_params(float thresh_dist, float thresh_dot); + // one function to do all the uv mapping and lightmap creation in one // (for godot lightmap workflow) - MeshInstance * rooms_convert_lightmap_internal(String szProxyFilename, String szLevelFilename); + MeshInstance * lightmap_internal(String szProxyFilename, String szLevelFilename); //______________________________________________________________________________________ // HELPERS @@ -123,6 +127,7 @@ public: Array rooms_get_visible_rooms() const; // helper func, not needed usually as dob_update returns the room int dob_get_room_id(Node * pDOB); + bool export_scene_DAE(Node * pNode, String szFilename); //______________________________________________________________________________________ @@ -284,6 +289,10 @@ private: // for debugging, can emulate view frustum culling bool m_bFrustumOnly; + // lightmap unmerge params + float m_fLightmapUnMerge_ThresholdDist; + float m_fLightmapUnMerge_ThresholdDot; + private: // PRIVATE FUNCS // this is where we do all the culling