From 92d4377ca6b06dec2248c78fbce8eeddef8cd291 Mon Sep 17 00:00:00 2001 From: SeriousAlexej Date: Sun, 14 Nov 2021 01:37:18 +0200 Subject: [PATCH 1/5] Greatly optimize model creation --- Sources/Engine/Models/EditModel.cpp | 6 +++-- Sources/Engine/Models/ImportedMesh.cpp | 34 ++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Sources/Engine/Models/EditModel.cpp b/Sources/Engine/Models/EditModel.cpp index cd17b17f1..2b5ee7dcd 100644 --- a/Sources/Engine/Models/EditModel.cpp +++ b/Sources/Engine/Models/EditModel.cpp @@ -500,7 +500,8 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe } INDEX iO3D = 0; // index used for progress dialog - CStaticStackArray avVertices; // for caching all vertices in all frames + std::vector avVertices; // for caching all vertices in all frames + avVertices.reserve(baseMesh.m_vertices.size() * frameGenerators.size()); BOOL bOrigin = FALSE; FLOATmatrix3D mOrientation; @@ -549,7 +550,8 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe vVtx *= mOrientation; } OneFrameBB |= FLOATaabbox3D(vVtx); - avVertices.Push() = vVtx; // cache vertex + avVertices.emplace_back(); + avVertices.back() = vVtx; // cache vertex } OB3D.ob_aoscSectors[0].UnlockAll(); // remember this frame's Bounding Box diff --git a/Sources/Engine/Models/ImportedMesh.cpp b/Sources/Engine/Models/ImportedMesh.cpp index b450dbbe5..a738109bc 100644 --- a/Sources/Engine/Models/ImportedMesh.cpp +++ b/Sources/Engine/Models/ImportedMesh.cpp @@ -241,16 +241,40 @@ ImportedMesh::ImportedMesh(const CTFileName& fnmFileName, const FLOATmatrix3D& m void ImportedMesh::ApplySkinning(const ImportedSkeleton& baseSkeleton, const ImportedSkeleton& animSkeleton, const FLOATmatrix3D& mTransform) { + struct _TransformsCache + { + public: + const FLOATmatrix4D& GetAbsoluteTransform(const ImportedSkeleton::Bone& bone) const + { + auto foundPos = m_transforms.find(&bone); + if (foundPos != m_transforms.end()) + return foundPos->second; + return m_transforms.insert({ &bone, bone.GetAbsoluteTransform() }).first->second; + } + const FLOATmatrix4D& GetInverseAbsoluteTransform(const ImportedSkeleton::Bone& bone) const + { + auto foundPos = m_inverseTransforms.find(&bone); + if (foundPos != m_inverseTransforms.end()) + return foundPos->second; + return m_inverseTransforms.insert({ &bone, InverseMatrix(bone.GetAbsoluteTransform()) }).first->second; + } + private: + mutable std::unordered_map m_transforms; + mutable std::unordered_map m_inverseTransforms; + }; + _TransformsCache transformCache; + + const auto inverseMeshTransform = InverseMatrix(mTransform); for (size_t v = 0; v < m_vertices.size(); ++v) { + const auto& weights = m_verticeWeights[v]; + if (weights.empty()) + continue; auto& vtx3D = m_vertices[v]; - auto vtxUnTransformed = FLOAT3D(-vtx3D(1), vtx3D(2), -vtx3D(3)) * InverseMatrix(mTransform); + auto vtxUnTransformed = FLOAT3D(-vtx3D(1), vtx3D(2), -vtx3D(3)) * inverseMeshTransform; const FLOAT4D vertex(vtxUnTransformed(1), vtxUnTransformed(2), vtxUnTransformed(3), 1.0f); FLOAT4D result(0, 0, 0, 0); - const auto& weights = m_verticeWeights[v]; - if (weights.empty()) - continue; for (const auto& weight : weights) { const auto& boneName = m_bonesNames[weight.first]; @@ -259,7 +283,7 @@ void ImportedMesh::ApplySkinning(const ImportedSkeleton& baseSkeleton, const Imp continue; const auto& baseBone = baseIt->second; const auto& animBone = animSkeleton.m_bones.find(boneName)->second; - const FLOATmatrix4D transform = animBone.GetAbsoluteTransform() * InverseMatrix(baseBone.GetAbsoluteTransform()); + const FLOATmatrix4D transform = transformCache.GetAbsoluteTransform(animBone) * transformCache.GetInverseAbsoluteTransform(baseBone); result += (vertex * transform) * weight.second; } From e34af58c6ad9f98457e959aa3170761d1366d5f2 Mon Sep 17 00:00:00 2001 From: SeriousAlexej Date: Mon, 15 Nov 2021 14:59:06 +0200 Subject: [PATCH 2/5] Fix crash on mip generation, eliminate usage of CObject3D in modeler --- Sources/Engine/Models/EditModel.cpp | 781 ++++++++++++--------------- Sources/Engine/Models/EditModel.h | 9 +- Sources/Engine/Models/ImportedMesh.h | 2 +- Sources/Engine/Models/MipMaker.cpp | 90 ++- Sources/Engine/Models/MipMaker.h | 8 +- Sources/Modeler/ModelerView.cpp | 139 ++--- 6 files changed, 453 insertions(+), 576 deletions(-) diff --git a/Sources/Engine/Models/EditModel.cpp b/Sources/Engine/Models/EditModel.cpp index 2b5ee7dcd..c439c66c1 100644 --- a/Sources/Engine/Models/EditModel.cpp +++ b/Sources/Engine/Models/EditModel.cpp @@ -43,8 +43,8 @@ CProgressRoutines ProgresRoutines; // constants important to this module #define MAX_ALLOWED_DISTANCE 0.0001f -#define PC_ALLWAYS_ON (1UL << 30) -#define PC_ALLWAYS_OFF (1UL << 31) +#define PC_ALLWAYS_ON (1UL << 30) +#define PC_ALLWAYS_OFF (1UL << 31) // origin triangle for transforming object @@ -60,16 +60,16 @@ void CThumbnailSettings::Read_t( CTStream *strFile) *strFile>>ts_bSet; *strFile>>ts_plLightPlacement; *strFile>>ts_plModelPlacement; - *strFile>>ts_fTargetDistance; - *strFile>>ts_vTarget; - *strFile>>ts_angViewerOrientation; + *strFile>>ts_fTargetDistance; + *strFile>>ts_vTarget; + *strFile>>ts_angViewerOrientation; *strFile>>ts_LightDistance; *strFile>>ts_LightColor; *strFile>>ts_colAmbientColor; - *strFile>>ts_PaperColor; - *strFile>>ts_InkColor; - *strFile>>ts_IsWinBcgTexture; - *strFile>>ts_WinBcgTextureName; + *strFile>>ts_PaperColor; + *strFile>>ts_InkColor; + *strFile>>ts_IsWinBcgTexture; + *strFile>>ts_WinBcgTextureName; ts_RenderPrefs.Read_t( strFile); } @@ -78,16 +78,16 @@ void CThumbnailSettings::Write_t( CTStream *strFile) *strFile< CEditModel::LoadFrameGenerators(CAnimDat frames.emplace_back(); auto& frame = frames.back(); frame.m_filename = sourceFile.c_str(); - frame.m_generator = [&baseMesh, &skeleton, mStretch, importedAnimation, frameIndex](CObject3D& outObject) + frame.m_generator = [&baseMesh, &skeleton, mStretch, importedAnimation, frameIndex](ImportedMesh& mesh) { - auto skinnedMesh = baseMesh; + mesh = baseMesh; const auto& animSkeleton = importedAnimation->m_frames[frameIndex]; - skinnedMesh.ApplySkinning(skeleton, animSkeleton, mStretch); - outObject.Clear(); - outObject.FillFromMesh(skinnedMesh); + mesh.ApplySkinning(skeleton, animSkeleton, mStretch); }; } @@ -404,10 +402,9 @@ std::vector CEditModel::LoadFrameGenerators(CAnimDat frames.emplace_back(); auto& frame = frames.back(); frame.m_filename = *itStrFrame; - frame.m_generator = [mStretch, filename = *itStrFrame](CObject3D& outObject) + frame.m_generator = [mStretch, filename = *itStrFrame](ImportedMesh& mesh) { - outObject.Clear(); - outObject.FillFromMesh(ImportedMesh(filename, mStretch)); + mesh.FillFromFile(filename, mStretch); }; } poaOneAnim->oa_FrameIndices[iFrame] = frameIndex; @@ -457,33 +454,31 @@ struct VertexNeighbors { CStaticStackArray vp_aiNeighbors; }; void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMesh, ImportedSkeleton& skeleton, const FLOATmatrix3D &mStretch) // throw char * { INDEX i; - CObject3D OB3D; - FLOATaabbox3D OneFrameBB; - FLOATaabbox3D AllFramesBB; + FLOATaabbox3D OneFrameBB; + FLOATaabbox3D AllFramesBB; INDEX ctFramesBefore = edm_md.md_FramesCt; edm_md.ClearAnimations(); - OB3D.ob_aoscSectors.Lock(); - // there must be at least one mip model loaded, throw if not - if( edm_md.md_VerticesCt == 0) { - throw( "Trying to update model's animations, but model doesn't exists!"); - } + // there must be at least one mip model loaded, throw if not + if( edm_md.md_VerticesCt == 0) { + throw( "Trying to update model's animations, but model doesn't exists!"); + } auto frameGenerators = LoadFrameGenerators(edm_md, pFile, baseMesh, skeleton, mStretch); // if recreating animations, frame count must be the same if( (ctFramesBefore != 0) && (frameGenerators.size() != ctFramesBefore) ) { - throw( "If you are updating animations, you can't change number of frames. \ + throw( "If you are updating animations, you can't change number of frames. \ If you want to add or remove some frames or animations, please recreate the model."); } - edm_md.md_FramesCt = frameGenerators.size(); + edm_md.md_FramesCt = frameGenerators.size(); - /* - * Now we will allocate frames and frames info array and array od 3D objects, - * one for each frame. - */ + /* + * Now we will allocate frames and frames info array and array od 3D objects, + * one for each frame. + */ if( ProgresRoutines.SetProgressMessage != NULL) { ProgresRoutines.SetProgressMessage( "Calculating bounding boxes ..."); @@ -493,13 +488,13 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe } edm_md.md_FrameInfos.New( edm_md.md_FramesCt); - if( edm_md.md_Flags & MF_COMPRESSED_16BIT) { + if( edm_md.md_Flags & MF_COMPRESSED_16BIT) { edm_md.md_FrameVertices16.New( edm_md.md_FramesCt * edm_md.md_VerticesCt); } else { edm_md.md_FrameVertices8.New( edm_md.md_FramesCt * edm_md.md_VerticesCt); } - INDEX iO3D = 0; // index used for progress dialog + INDEX iO3D = 0; // index used for progress dialog std::vector avVertices; // for caching all vertices in all frames avVertices.reserve(baseMesh.m_vertices.size() * frameGenerators.size()); @@ -512,18 +507,20 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe } for (auto& frameGenerator : frameGenerators) - { + { if( ProgresRoutines.SetProgressState != NULL) ProgresRoutines.SetProgressState(iO3D); - frameGenerator.m_generator(OB3D); - if( edm_md.md_VerticesCt != OB3D.ob_aoscSectors[0].osc_aovxVertices.Count()) { - ThrowF_t( "File %s, one of animation frame files has wrong number of points.", + ImportedMesh mesh; + frameGenerator.m_generator(mesh); + + if( edm_md.md_VerticesCt != mesh.m_vertices.size()) { + ThrowF_t( "File %s, one of animation frame files has wrong number of points.", frameGenerator.m_filename); - } + } if(bOrigin) { // calc matrix for vertex transform - FLOAT3D vY = DOUBLEtoFLOAT(OB3D.ob_aoscSectors[0].osc_aovxVertices[aiTransVtx[2]]-OB3D.ob_aoscSectors[0].osc_aovxVertices[aiTransVtx[0]]); - FLOAT3D vZ = DOUBLEtoFLOAT(OB3D.ob_aoscSectors[0].osc_aovxVertices[aiTransVtx[0]]-OB3D.ob_aoscSectors[0].osc_aovxVertices[aiTransVtx[1]]); + FLOAT3D vY = mesh.m_vertices[aiTransVtx[2]]-mesh.m_vertices[aiTransVtx[0]]; + FLOAT3D vZ = mesh.m_vertices[aiTransVtx[0]]-mesh.m_vertices[aiTransVtx[1]]; FLOAT3D vX = vY*vZ; vY = vZ*vX; // make a rotation matrix from those vectors @@ -538,32 +535,30 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe } // normalize (clear) our Bounding Box - OB3D.ob_aoscSectors[0].LockAll(); - OneFrameBB = FLOATaabbox3D(); + OneFrameBB = FLOATaabbox3D(); // Bounding Box makes union with all points in this frame - for( i=0; i avnVertices; avnVertices.New( edm_md.md_VerticesCt); - - // lost 1st frame (one frame is enough because all frames has same poly->edge->vertex links) - OB3D.Clear(); - OB3D.FillFromMesh(baseMesh); - OB3D.ob_aoscSectors[0].LockAll(); // loop thru polygons - INDEX iPolyNo=0; - {FOREACHINDYNAMICARRAY( OB3D.ob_aoscSectors[0].osc_aopoPolygons, CObjectPolygon, itPoly) - { - CObjectPolygon &opo = *itPoly; - // get all 3 vetrices of current polygon and sorted them - opo.opo_PolygonEdges.Lock(); - CObjectPolygonEdge &opeCurr = opo.opo_PolygonEdges[0]; - CObjectPolygonEdge &opeNext = opo.opo_PolygonEdges[1]; - CObjectVertex *povxCurr, *povxPrev, *povxNext; - if( !opeCurr.ope_Backward) { - povxCurr = opeCurr.ope_Edge->oed_Vertex1; - povxPrev = opeCurr.ope_Edge->oed_Vertex0; - ASSERT( opeNext.ope_Edge->oed_Vertex0 == povxCurr); - } else { - povxCurr = opeCurr.ope_Edge->oed_Vertex0; - povxPrev = opeCurr.ope_Edge->oed_Vertex1; - ASSERT( opeNext.ope_Edge->oed_Vertex1 == povxCurr); - } - if( !opeNext.ope_Backward) { - povxNext = opeNext.ope_Edge->oed_Vertex1; - ASSERT( opeNext.ope_Edge->oed_Vertex0 == povxCurr); - } else { - povxNext = opeNext.ope_Edge->oed_Vertex0; - ASSERT( opeNext.ope_Edge->oed_Vertex1 == povxCurr); - } - INDEX iVtx0 = OB3D.ob_aoscSectors[0].osc_aovxVertices.Index(povxPrev); - INDEX iVtx1 = OB3D.ob_aoscSectors[0].osc_aovxVertices.Index(povxCurr); - INDEX iVtx2 = OB3D.ob_aoscSectors[0].osc_aovxVertices.Index(povxNext); + for (const auto& triangle : baseMesh.m_triangles) + { + INDEX iVtx0 = triangle.ct_iVtx[0]; + INDEX iVtx1 = triangle.ct_iVtx[1]; + INDEX iVtx2 = triangle.ct_iVtx[2]; // add neighbor vertices for each of this vertices avnVertices[iVtx0].vp_aiNeighbors.Push() = iVtx2; avnVertices[iVtx0].vp_aiNeighbors.Push() = iVtx1; @@ -615,13 +582,8 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe avnVertices[iVtx1].vp_aiNeighbors.Push() = iVtx2; avnVertices[iVtx2].vp_aiNeighbors.Push() = iVtx1; avnVertices[iVtx2].vp_aiNeighbors.Push() = iVtx0; - // advance to next poly - opo.opo_PolygonEdges.Unlock(); - iPolyNo++; - }} + } // vertex->polygons links created - OB3D.ob_aoscSectors[0].UnlockAll(); - // cache strecthing reciprocal for faster calc FLOAT f1oStretchX, f1oStretchY, f1oStretchZ; @@ -638,7 +600,7 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe // remember center vector FLOAT3D vCenter = AllFramesBB.Center(); // obtain bbox center edm_md.md_vCenter = vCenter; - + // prepare progress bar if( ProgresRoutines.SetProgressMessage != NULL) { ProgresRoutines.SetProgressMessage( "Calculating gouraud normals and stretching vertices ..."); @@ -649,29 +611,29 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe // loop thru frames iO3D=0; // index for progress - INDEX iFVtx=0; // count for all vertices in all frames + INDEX iFVtx=0; // count for all vertices in all frames for( INDEX iFr=0; iFr=0 && a<=180); aSum += a; vSum += (v/fLength) * a; - } + } // normalize sum of polygon normals //ASSERT( aSum>=0); @@ -695,16 +657,16 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe vSum.Normalize(); // save compressed gouraud normal - if( edm_md.md_Flags & MF_COMPRESSED_16BIT) { + if( edm_md.md_Flags & MF_COMPRESSED_16BIT) { CompressNormal_HQ( vSum, edm_md.md_FrameVertices16[iFVtx].mfv_ubNormH, edm_md.md_FrameVertices16[iFVtx].mfv_ubNormP); } else { - edm_md.md_FrameVertices8[iFVtx].mfv_NormIndex = (UBYTE)GouraudNormal(vSum); + edm_md.md_FrameVertices8[iFVtx].mfv_NormIndex = (UBYTE)GouraudNormal(vSum); } // advance to next vertex in model - iFVtx++; - } + iFVtx++; + } // advance to next frame iO3D++; @@ -725,9 +687,6 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe edm_md.md_Stretch(2) /= 127.0f; edm_md.md_Stretch(3) /= 127.0f; } - - // all done - OB3D.ob_aoscSectors.Unlock(); } @@ -1287,23 +1246,21 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * { INDEX i; CTFileStream File; - CObject3D O3D; - char ld_line[ 128]; - char flag_str[ 128]; - char base_path[ PATH_MAX] = ""; - char file_name[ PATH_MAX]; + char ld_line[ 128]; + char flag_str[ 128]; + char base_path[ PATH_MAX] = ""; + char file_name[ PATH_MAX]; char mapping_file_name[ PATH_MAX] = ""; - char full_path[ PATH_MAX]; + char full_path[ PATH_MAX]; FLOATmatrix3D mStretch; mStretch.Diagonal(1.0f); - BOOL bMappingDimFound ; - BOOL bAnimationsFound; + BOOL bMappingDimFound ; + BOOL bAnimationsFound; BOOL bLoadInitialMapping; ImportedMesh baseMesh; ImportedSkeleton skeleton; - O3D.ob_aoscSectors.Lock(); - File.Open_t( fnScriptName); // open script file for reading + File.Open_t( fnScriptName); // open script file for reading // to hold number of line's chars int iLineChars; @@ -1335,10 +1292,10 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * continue; } - if (EQUAL_SUB_STR("ANIMATION ")) - hasRegularAnimation = true; - else if (EQUAL_SUB_STR("SKELETAL_ANIMATION ")) + if (EQUAL_SUB_STR("SKELETAL_ANIMATION ")) hasSkeletalAnimation = true; + else if (EQUAL_SUB_STR("ANIMATION ")) + hasRegularAnimation = true; else if (EQUAL_SUB_STR("NO_BONE_TRIANGLES")) { allowedToCreateBoneTriangles = false; @@ -1347,94 +1304,94 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * } File.SetPos_t(startPos); - // if these flags will not be TRUE at the end of script, throw error - bMappingDimFound = FALSE; - bAnimationsFound = FALSE; + // if these flags will not be TRUE at the end of script, throw error + bMappingDimFound = FALSE; + bAnimationsFound = FALSE; bLoadInitialMapping = FALSE; - FOREVER - { - do + FOREVER + { + do { File.GetLine_t(ld_line, 128); iLineChars = strlen( ld_line); } - while( (iLineChars == 0) || (ld_line[0]==';') ); + while( (iLineChars == 0) || (ld_line[0]==';') ); - // If key-word is "DIRECTORY", remember base path it and add "\" character at the - // end of new path if it is not yet there - if( EQUAL_SUB_STR( "DIRECTORY")) - { - _strupr( ld_line); + // If key-word is "DIRECTORY", remember base path it and add "\" character at the + // end of new path if it is not yet there + if( EQUAL_SUB_STR( "DIRECTORY")) + { + _strupr( ld_line); sscanf( ld_line, "DIRECTORY %s", base_path); - if( base_path[ strlen( base_path) - 1] != '\\') - strcat( base_path,"\\"); - } - // Key-word "SIZE" defines stretch factor - else if( EQUAL_SUB_STR( "SIZE")) - { - _strupr( ld_line); + if( base_path[ strlen( base_path) - 1] != '\\') + strcat( base_path,"\\"); + } + // Key-word "SIZE" defines stretch factor + else if( EQUAL_SUB_STR( "SIZE")) + { + _strupr( ld_line); FLOAT fStretch = 1.0f; - sscanf( ld_line, "SIZE %g", &fStretch); + sscanf( ld_line, "SIZE %g", &fStretch); mStretch *= fStretch; - } - else if( EQUAL_SUB_STR( "TRANSFORM")) + } + else if( EQUAL_SUB_STR( "TRANSFORM")) { - _strupr( ld_line); + _strupr( ld_line); FLOATmatrix3D mTran; mTran.Diagonal(1.0f); - sscanf( ld_line, "TRANSFORM %g %g %g %g %g %g %g %g %g", + sscanf( ld_line, "TRANSFORM %g %g %g %g %g %g %g %g %g", &mTran(1,1), &mTran(1,2), &mTran(1,3), &mTran(2,1), &mTran(2,2), &mTran(2,3), &mTran(3,1), &mTran(3,2), &mTran(3,3)); mStretch *= mTran; } - // Key-word "FLAT" means that model will be mapped as face - forward, using only + // Key-word "FLAT" means that model will be mapped as face - forward, using only // zooming of texture - else if( EQUAL_SUB_STR( "FLAT")) - { - _strupr( ld_line); - sscanf( ld_line, "FLAT %s", flag_str); + else if( EQUAL_SUB_STR( "FLAT")) + { + _strupr( ld_line); + sscanf( ld_line, "FLAT %s", flag_str); if( strcmp( flag_str, "YES") == 0) { edm_md.md_Flags |= MF_FACE_FORWARD; edm_md.md_Flags &= ~MF_HALF_FACE_FORWARD; } - } - else if( EQUAL_SUB_STR( "HALF_FLAT")) - { - _strupr( ld_line); - sscanf( ld_line, "HALF_FLAT %s", flag_str); + } + else if( EQUAL_SUB_STR( "HALF_FLAT")) + { + _strupr( ld_line); + sscanf( ld_line, "HALF_FLAT %s", flag_str); if( strcmp( flag_str, "YES") == 0) edm_md.md_Flags |= MF_FACE_FORWARD|MF_HALF_FACE_FORWARD; - } + } else if( EQUAL_SUB_STR( "STRETCH_DETAIL")) { - _strupr( ld_line); - sscanf( ld_line, "STRETCH_DETAIL %s", flag_str); + _strupr( ld_line); + sscanf( ld_line, "STRETCH_DETAIL %s", flag_str); if( strcmp( flag_str, "YES") == 0) { edm_md.md_Flags |= MF_STRETCH_DETAIL; } } - else if( EQUAL_SUB_STR( "HI_QUALITY")) - { - _strupr( ld_line); - sscanf( ld_line, "HI_QUALITY %s", flag_str); + else if( EQUAL_SUB_STR( "HI_QUALITY")) + { + _strupr( ld_line); + sscanf( ld_line, "HI_QUALITY %s", flag_str); if( strcmp( flag_str, "YES") == 0) { edm_md.md_Flags |= MF_COMPRESSED_16BIT; } - } - // Key-word "REFLECTIONS" has been used in old reflections - else if( EQUAL_SUB_STR( "REFLECTIONS")) + } + // Key-word "REFLECTIONS" has been used in old reflections + else if( EQUAL_SUB_STR( "REFLECTIONS")) { } - // Key-word "MAX_SHADOW" determines maximum quality of shading that model can obtain - else if( EQUAL_SUB_STR( "MAX_SHADOW")) + // Key-word "MAX_SHADOW" determines maximum quality of shading that model can obtain + else if( EQUAL_SUB_STR( "MAX_SHADOW")) { - _strupr( ld_line); - INDEX iShadowQuality; + _strupr( ld_line); + INDEX iShadowQuality; sscanf( ld_line, "MAX_SHADOW %d", &iShadowQuality); edm_md.md_ShadowQuality = iShadowQuality; } @@ -1445,15 +1402,15 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * sprintf(full_path, "%s%s", base_path, file_name); skeleton.FillFromFile(CTString(full_path)); } - // Key-word "MipModel" must follow name of this mipmodel file + // Key-word "MipModel" must follow name of this mipmodel file else if( EQUAL_SUB_STR( "MIP_MODELS")) { - INDEX iMipCt; + INDEX iMipCt; sscanf( ld_line, "MIP_MODELS %d", &iMipCt); if( (iMipCt <= 0) || (iMipCt >= MAX_MODELMIPS)) - { - ThrowF_t("Invalid number of mip models. Number must range from 0 to %d.", MAX_MODELMIPS-1); - } + { + ThrowF_t("Invalid number of mip models. Number must range from 0 to %d.", MAX_MODELMIPS-1); + } if( ProgresRoutines.SetProgressMessage != NULL) ProgresRoutines.SetProgressMessage( "Loading and creating mip-models ..."); if( ProgresRoutines.SetProgressRange != NULL) @@ -1462,14 +1419,14 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * { if( ProgresRoutines.SetProgressState != NULL) ProgresRoutines.SetProgressState( i); - do + do { File.GetLine_t(ld_line, 128); } - while( (strlen( ld_line)== 0) || (ld_line[0]==';')); - _strupr( ld_line); - sscanf( ld_line, "%s", file_name); - sprintf( full_path, "%s%s", base_path, file_name); + while( (strlen( ld_line)== 0) || (ld_line[0]==';')); + _strupr( ld_line); + sscanf( ld_line, "%s", file_name); + sprintf( full_path, "%s%s", base_path, file_name); if (skeleton.Empty()) skeleton.FillFromFile(CTString(full_path)); ImportedMesh mesh(CTString(full_path), mStretch); @@ -1479,85 +1436,81 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * CreateBoneTriangles(mesh, skeleton, mStretch); baseMesh = mesh; } - O3D.Clear(); // clear possible existing O3D's data - O3D.FillFromMesh(baseMesh); // If there are no vertices in model, call New Model and calculate UV mapping - if( edm_md.md_VerticesCt == 0) - { - if( bMappingDimFound == FALSE) - { - ThrowF_t("Found key word \"MIP_MODELS\" but texture dimension wasn't found.\n" - "There must be key word \"TEXTURE_DIM\" before key word \"MIP_MODELS\" in script file."); - } - NewModel( &O3D); - } + if( edm_md.md_VerticesCt == 0) + { + if( bMappingDimFound == FALSE) + { + ThrowF_t("Found key word \"MIP_MODELS\" but texture dimension wasn't found.\n" + "There must be key word \"TEXTURE_DIM\" before key word \"MIP_MODELS\" in script file."); + } + NewModel(mesh); + } else { - O3D.ob_aoscSectors[0].LockAll(); - AddMipModel( &O3D); // else this is one of model's mip definitions so call Add Mip Model - O3D.ob_aoscSectors[0].UnlockAll(); + AddMipModel(mesh); } - } + } // set default mip factors // all mip models will be spreaded beetween distance 0 and default maximum distance edm_md.SpreadMipSwitchFactors( 0, 5.0f); } - /* - * Line containing key-word "TEXTURE_DIM" gives us texture dimensions - * so we can create default mapping - */ - else if( EQUAL_SUB_STR( "TEXTURE_DIM")) - { - _strupr( ld_line); - FLOAT fWidth, fHeight; - sscanf( ld_line, "TEXTURE_DIM %f %f", &fWidth, &fHeight); // read given texture dimensions - edm_md.md_Width = MEX_METERS( fWidth); + /* + * Line containing key-word "TEXTURE_DIM" gives us texture dimensions + * so we can create default mapping + */ + else if( EQUAL_SUB_STR( "TEXTURE_DIM")) + { + _strupr( ld_line); + FLOAT fWidth, fHeight; + sscanf( ld_line, "TEXTURE_DIM %f %f", &fWidth, &fHeight); // read given texture dimensions + edm_md.md_Width = MEX_METERS( fWidth); edm_md.md_Height = MEX_METERS( fHeight); bMappingDimFound = TRUE; - } - // Key-word "ANIM_START" starts loading of Animation Data object - else if( EQUAL_SUB_STR( "ANIM_START")) - { - LoadModelAnimationData_t( &File, baseMesh, skeleton, mStretch); // loads and sets model's animation data + } + // Key-word "ANIM_START" starts loading of Animation Data object + else if( EQUAL_SUB_STR( "ANIM_START")) + { + LoadModelAnimationData_t( &File, baseMesh, skeleton, mStretch); // loads and sets model's animation data // add one collision box edm_md.md_acbCollisionBox.New(); // reset attaching sounds CreateEmptyAttachingSounds(); - bAnimationsFound = TRUE; // mark that we found animations section in script-file - } + bAnimationsFound = TRUE; // mark that we found animations section in script-file + } else if( EQUAL_SUB_STR( "ORIGIN_TRI")) { - sscanf( ld_line, "ORIGIN_TRI %d %d %d", &aiTransVtx[0], &aiTransVtx[1], &aiTransVtx[2]); // read given vertices + sscanf( ld_line, "ORIGIN_TRI %d %d %d", &aiTransVtx[0], &aiTransVtx[1], &aiTransVtx[2]); // read given vertices + } + // Key-word "END" ends infinite loop and script loading is over + else if( EQUAL_SUB_STR( "END")) + { + break; } - // Key-word "END" ends infinite loop and script loading is over - else if( EQUAL_SUB_STR( "END")) - { - break; - } else if (EQUAL_SUB_STR("NO_BONE_TRIANGLES")) {} // ignore old key-words else if( EQUAL_SUB_STR( "MAPPING")) {} - else if( EQUAL_SUB_STR( "TEXTURE_REFLECTION")) {} - else if( EQUAL_SUB_STR( "TEXTURE_SPECULAR")) {} - else if( EQUAL_SUB_STR( "TEXTURE_BUMP")) {} - else if( EQUAL_SUB_STR( "TEXTURE")) {} + else if( EQUAL_SUB_STR( "TEXTURE_REFLECTION")) {} + else if( EQUAL_SUB_STR( "TEXTURE_SPECULAR")) {} + else if( EQUAL_SUB_STR( "TEXTURE_BUMP")) {} + else if( EQUAL_SUB_STR( "TEXTURE")) {} else if( EQUAL_SUB_STR( "DEFINE_MAPPING")) {} else if( EQUAL_SUB_STR( "IMPORT_MAPPING")) {} - // If none of known key-words isnt recognised, we have wierd key-word, so throw error - else - { + // If none of known key-words isnt recognised, we have wierd key-word, so throw error + else + { ThrowF_t("Unrecognizible key-word found in line: \"%s\".", ld_line); - } - } - /* - * At the end we check if we found animations in script file and if initial mapping was done - * during loading of script file what means that key-word 'TEXTURE_DIM' was found - */ - if( bAnimationsFound != TRUE) - throw( "There are no animations defined for this model, and that can't be. Probable cause: script missing key-word \"ANIM_START\"."); - - if( bMappingDimFound != TRUE) - throw( "Initial mapping not done, and that can't be. Probable cause: script missing key-word \"TEXTURE_DIM\"."); + } + } + /* + * At the end we check if we found animations in script file and if initial mapping was done + * during loading of script file what means that key-word 'TEXTURE_DIM' was found + */ + if( bAnimationsFound != TRUE) + throw( "There are no animations defined for this model, and that can't be. Probable cause: script missing key-word \"ANIM_START\"."); + + if( bMappingDimFound != TRUE) + throw( "Initial mapping not done, and that can't be. Probable cause: script missing key-word \"TEXTURE_DIM\"."); edm_md.LinkDataForSurfaces(TRUE); @@ -1576,7 +1529,6 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * CalculateMappingForMips(); - O3D.ob_aoscSectors.Unlock(); File.Close(); if( edm_aasAttachedSounds.Count() == 0) @@ -1588,28 +1540,22 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * * Routine takes Object 3D class as input and creates new model (model data) * with its polygons, vertices, surfaces */ -void CEditModel::NewModel(CObject3D *pO3D) +void CEditModel::NewModel(const ImportedMesh& mesh) { - pO3D->ob_aoscSectors.Lock(); - pO3D->ob_aoscSectors[0].LockAll(); - edm_md.md_VerticesCt = pO3D->ob_aoscSectors[0].osc_aovxVertices.Count(); // see how many vertices we will have - edm_md.md_TransformedVertices.New( edm_md.md_VerticesCt); // create buffer for rotated vertices + edm_md.md_VerticesCt = mesh.m_vertices.size(); // see how many vertices we will have + edm_md.md_TransformedVertices.New( edm_md.md_VerticesCt); // create buffer for rotated vertices edm_md.md_MainMipVertices.New( edm_md.md_VerticesCt); // create buffer for main mip vertices - edm_md.md_VertexMipMask.New( edm_md.md_VerticesCt); // create buffer for vertex masks + edm_md.md_VertexMipMask.New( edm_md.md_VerticesCt); // create buffer for vertex masks for( INDEX i=0; iob_aoscSectors[0].osc_aovxVertices[ i]); - edm_md.md_VertexMipMask[ i] = 0L; // mark to all vertices that they don't exist in any mip-model - } - - AddMipModel(pO3D); // we add main model, first mip-model + // mip-models later (we will search original coordinates in this array) + edm_md.md_MainMipVertices[ i] = mesh.m_vertices[i]; + edm_md.md_VertexMipMask[i] = 0L; // mark to all vertices that they don't exist in any mip-model + } - pO3D->ob_aoscSectors[0].UnlockAll(); - pO3D->ob_aoscSectors.Unlock(); + AddMipModel(mesh); // we add main model, first mip-model } //---------------------------------------------------------------------------------------------- @@ -1619,14 +1565,14 @@ void CEditModel::NewModel(CObject3D *pO3D) * array. If minimum distance is found, set that this vertice exists. Loop for all vertices. * Throw error if minimum distance isn't found. Set also new mip-model polygons info. */ -void CEditModel::AddMipModel( CObject3D *pO3D) +void CEditModel::AddMipModel(const ImportedMesh& mesh) { INDEX i, j; // this is mask for vertices in current mip level ULONG mip_vtx_mask = (1L) << edm_md.md_MipCt; - struct ModelMipInfo *pmmpi = &edm_md.md_MipInfos[ edm_md.md_MipCt]; // point to mip model that we will create + struct ModelMipInfo *pmmpi = &edm_md.md_MipInfos[ edm_md.md_MipCt]; // point to mip model that we will create // for each vertex for( INDEX iVertex=0; iVertexob_aoscSectors[0].osc_aovxVertices.Count(); - /* - * For each vertex in 3D object we calculate distances to all vertices in main mip-model. - * If distance (size of vector that is result of substraction of two vertice vectors) is - * less than some minimal float number, we assume that these vertices are the same. - * Processed vertex of 3D object gets its main-mip-model-vertex-friend's index as tag and - * mask value showing that it exists in this mip-model. - */ - for( i=0; i verticesRemap(mesh.m_vertices.size(), 0); + for( i=0; iob_aoscSectors[0].osc_aovxVertices[i]); + FLOAT3D vVertex = mesh.m_vertices[i]; FLOAT fAbsoluteDistance = Abs((vVertex - edm_md.md_MainMipVertices[j]).Length()); if (fAbsoluteDistance < MAX_ALLOWED_DISTANCE) { @@ -1665,50 +1612,50 @@ void CEditModel::AddMipModel( CObject3D *pO3D) } } - if (same_index == -1) // if no vertice close enough is found, we have error + if (same_index == -1) // if no vertice close enough is found, we have error { ThrowF_t("Vertex from mip model %d with number %d, coordinates (%f,%f,%f), can't be found in main mip model.\n" "There can't be new vertices in rougher mip-models," "but only vertices from main mip model can be removed and polygons reorganized.\n", edm_md.md_MipCt, i, - pO3D->ob_aoscSectors[0].osc_aovxVertices[i](1), pO3D->ob_aoscSectors[0].osc_aovxVertices[i](2), pO3D->ob_aoscSectors[0].osc_aovxVertices[i](3)); + mesh.m_vertices[i](1), mesh.m_vertices[i](2), mesh.m_vertices[i](3)); } edm_md.md_VertexMipMask[same_index] |= mip_vtx_mask; // we mark that this vertice exists in this mip model - pO3D->ob_aoscSectors[0].osc_aovxVertices[i].ovx_Tag = same_index; // remapping verice index must be remembered - } - - /* - * We will create three arays for this mip polygon info: - * 1) array for polygons - * 2) array for mapping surfaces - * 3) array for polygon vertices - * 4) array for texture vertices - */ - - /* - * First we create array large enough to accept object 3D's polygons. - */ - pmmpi->mmpi_PolygonsCt = pO3D->ob_aoscSectors[0].osc_aopoPolygons.Count(); - pmmpi->mmpi_Polygons.New( pmmpi->mmpi_PolygonsCt); - - /* - * Then we will create array for mapping surfaces and set their names - */ - pmmpi->mmpi_MappingSurfaces.New( pO3D->ob_aoscSectors[0].osc_aomtMaterials.Count()); // create array for mapping surfaces - for( i=0; iob_aoscSectors[0].osc_aomtMaterials.Count(); i++) - { + verticesRemap[i] = same_index; // remapping verice index must be remembered + } + + /* + * We will create three arays for this mip polygon info: + * 1) array for polygons + * 2) array for mapping surfaces + * 3) array for polygon vertices + * 4) array for texture vertices + */ + + /* + * First we create array large enough to accept object 3D's polygons. + */ + pmmpi->mmpi_PolygonsCt = mesh.m_triangles.size(); + pmmpi->mmpi_Polygons.New( pmmpi->mmpi_PolygonsCt); + + /* + * Then we will create array for mapping surfaces and set their names + */ + pmmpi->mmpi_MappingSurfaces.New(mesh.m_materials.size()); // create array for mapping surfaces + for( i=0; immpi_MappingSurfaces[ i]; - ms.ms_ulOnColor = PC_ALLWAYS_ON; // set default ON and OFF masking colors - ms.ms_ulOffColor = PC_ALLWAYS_OFF; - ms.ms_Name = CTFileName( pO3D->ob_aoscSectors[0].osc_aomtMaterials[ i].omt_Name); + ms.ms_ulOnColor = PC_ALLWAYS_ON; // set default ON and OFF masking colors + ms.ms_ulOffColor = PC_ALLWAYS_OFF; + ms.ms_Name = CTFileName( mesh.m_materials[i].cm_strName); ms.ms_colColor = - pO3D->ob_aoscSectors[0].osc_aomtMaterials[ i].omt_Color | CT_OPAQUE; // copy surface color, set no alpha + mesh.m_materials[i].cm_colColor | CT_OPAQUE; // copy surface color, set no alpha ms.ms_sstShadingType = SST_MATTE; ms.ms_sttTranslucencyType = STT_OPAQUE; ms.ms_ulRenderingFlags = SRF_DIFFUSE|SRF_NEW_TEXTURE_FORMAT; - } + } struct VertexRemap { @@ -1736,25 +1683,14 @@ void CEditModel::AddMipModel( CObject3D *pO3D) std::unordered_map uniqueTexCoords; std::vector orderedUniqueTexCoords; std::vector texCoordsRemap; - {FOREACHINDYNAMICARRAY(pO3D->ob_aoscSectors[0].osc_aopoPolygons, CObjectPolygon, it1) + for (const auto& triangle : mesh.m_triangles) { - INDEX iPolySurface = pO3D->ob_aoscSectors[0].osc_aomtMaterials.Index(it1->opo_Material); - - CMappingVectors mappingVectors; - mappingVectors.FromPlane_DOUBLE(*(it1->opo_Plane)); - CMappingDefinition currentMapping = it1->opo_amdMappings[0]; - currentMapping.md_fVoS *= -1.0f; - currentMapping.md_fVoT *= -1.0f; - currentMapping.md_fUOffset *= -1.0f; - - FOREACHINDYNAMICARRAY(it1->opo_PolygonEdges, CObjectPolygonEdge, it2) + for (size_t e = 0; e < 3; ++e) { - DOUBLE3D* vtxPos = it2->ope_Edge->oed_Vertex0; - FLOAT2D vtxUV = currentMapping.GetTextureCoordinates(mappingVectors, DOUBLEtoFLOAT(*vtxPos)); - - INDEX globalIndex = pO3D->ob_aoscSectors[0].osc_aovxVertices.Index(it2->ope_Edge->oed_Vertex0); + FLOAT2D vtxUV(mesh.m_uvs[0][triangle.ct_iTVtx[0][e]]); + vtxUV(2) *= -1.0f; - VertexRemap vertex_remap{ vtxUV, iPolySurface, globalIndex }; + VertexRemap vertex_remap{ vtxUV, triangle.ct_iMaterial, triangle.ct_iVtx[e] }; auto found_pos = uniqueTexCoords.find(vertex_remap); if (found_pos == uniqueTexCoords.end()) { @@ -1767,7 +1703,7 @@ void CEditModel::AddMipModel( CObject3D *pO3D) texCoordsRemap.push_back(found_pos->second); } } - }} + } pmmpi->mmpi_TextureVertices.New(orderedUniqueTexCoords.size()); @@ -1790,35 +1726,32 @@ void CEditModel::AddMipModel( CObject3D *pO3D) * texture and transformed vertex ptrs) */ INDEX mpvct = 0; - for (i = 0; i < pmmpi->mmpi_PolygonsCt; i++) // loop all model polygons + for (i = 0; i < pmmpi->mmpi_PolygonsCt; i++) // loop all model polygons { - struct ModelPolygon* pmp = &pmmpi->mmpi_Polygons[i]; // ptr to activ model polygon - pmp->mp_Surface = pO3D->ob_aoscSectors[0].osc_aomtMaterials.Index(pO3D->ob_aoscSectors[0].osc_aopoPolygons[i].opo_Material); // copy surface index + const auto& triangle = mesh.m_triangles[i]; + struct ModelPolygon* pmp = &pmmpi->mmpi_Polygons[i]; // ptr to activ model polygon + pmp->mp_Surface = triangle.ct_iMaterial; // copy surface index pmp->mp_ColorAndAlpha = - pO3D->ob_aoscSectors[0].osc_aopoPolygons[i].opo_Material->omt_Color | CT_OPAQUE; // copy surface color, set no alpha + mesh.m_materials[triangle.ct_iMaterial].cm_colColor | CT_OPAQUE; // copy surface color, set no alpha - auto& o3d_polygon = pO3D->ob_aoscSectors[0].osc_aopoPolygons[i]; - - auto& polygon_edges = o3d_polygon.opo_PolygonEdges; - INDEX ctVertices = polygon_edges.Count(); // set no of polygon's vertices - pmp->mp_PolygonVertices.New(ctVertices); // create array for them - for (j = 0; j < ctVertices; j++) // fill data for this polygon's vertices + pmp->mp_PolygonVertices.New(3); // create array for them + for (j = 0; j < 3; j++) // fill data for this polygon's vertices { /* * Here we really remap one mip models's vertex in a way that we set its transformed * vertex ptr after remapping it using link (tag) to its original mip-model's vertex */ - CObjectVertex* o3d_vertex = polygon_edges[j].ope_Edge->oed_Vertex0; + INDEX o3d_vertex = triangle.ct_iVtx[j]; pmp->mp_PolygonVertices[j].mpv_ptvTransformedVertex = - &edm_md.md_TransformedVertices[(INDEX)o3d_vertex->ovx_Tag]; // remapped ptr to transformed vertex + &edm_md.md_TransformedVertices[verticesRemap[o3d_vertex]]; pmp->mp_PolygonVertices[j].mpv_ptvTextureVertex = &pmmpi->mmpi_TextureVertices[texCoordsRemap[mpvct++]]; } } - edm_md.md_MipCt ++; // finally, this mip-model is done. + edm_md.md_MipCt ++; // finally, this mip-model is done. } //---------------------------------------------------------------------------------------------- @@ -1885,7 +1818,7 @@ void CEditModel::CalculateMappingForMips( void) FLOAT3D vMainMipCoordPrev = edm_md.md_MainMipVertices[ iPrevMV]; // get distance of these two vertices FLOAT fAbsoluteDistance = Abs( (vMainMipCoordPrev - vMainMipCoordCur).Length()); - if( fAbsoluteDistance < fMinDistance) + if( fAbsoluteDistance < fMinDistance) { // remember current texture vertex as closest one fMinDistance = fAbsoluteDistance; @@ -1909,40 +1842,40 @@ void CEditModel::CalculateMappingForMips( void) */ void CEditModel::UpdateAnimations_t(CTFileName &fnScriptName) // throw char * { - CTFileStream File; - char ld_line[ 128]; + CTFileStream File; + char ld_line[ 128]; char base_path[PATH_MAX] = ""; char full_path[PATH_MAX]; char file_name[PATH_MAX]; - CListHead FrameNamesList; + CListHead FrameNamesList; ImportedMesh baseMesh; ImportedSkeleton skeleton; FLOATmatrix3D mStretch; mStretch.Diagonal(1.0f); - File.Open_t( fnScriptName); // open script file for reading + File.Open_t( fnScriptName); // open script file for reading FOREVER - { - do + { + do { File.GetLine_t(ld_line, 128); } - while( (strlen( ld_line)== 0) || (ld_line[0]==';')); + while( (strlen( ld_line)== 0) || (ld_line[0]==';')); - if( EQUAL_SUB_STR( "SIZE")) + if( EQUAL_SUB_STR( "SIZE")) { - _strupr( ld_line); + _strupr( ld_line); FLOAT fStretch = 1.0f; - sscanf( ld_line, "SIZE %g", &fStretch); + sscanf( ld_line, "SIZE %g", &fStretch); mStretch *= fStretch; } - else if( EQUAL_SUB_STR( "TRANSFORM")) + else if( EQUAL_SUB_STR( "TRANSFORM")) { - _strupr( ld_line); + _strupr( ld_line); FLOATmatrix3D mTran; mTran.Diagonal(1.0f); - sscanf( ld_line, "TRANSFORM %g %g %g %g %g %g %g %g %g", + sscanf( ld_line, "TRANSFORM %g %g %g %g %g %g %g %g %g", &mTran(1,1), &mTran(1,2), &mTran(1,3), &mTran(2,1), &mTran(2,2), &mTran(2,3), &mTran(3,1), &mTran(3,2), &mTran(3,3)); @@ -1976,35 +1909,33 @@ void CEditModel::UpdateAnimations_t(CTFileName &fnScriptName) // throw char * sprintf(full_path, "%s%s", base_path, file_name); baseMesh.FillFromFile(CTString(full_path), mStretch); } - else if( EQUAL_SUB_STR( "ANIM_START")) - { - LoadModelAnimationData_t( &File, baseMesh, skeleton, mStretch); // load and set model's animation data - break; // we found our animations, we loaded them so we will stop forever loop - } + else if( EQUAL_SUB_STR( "ANIM_START")) + { + LoadModelAnimationData_t( &File, baseMesh, skeleton, mStretch); // load and set model's animation data + break; // we found our animations, we loaded them so we will stop forever loop + } else if( EQUAL_SUB_STR( "ORIGIN_TRI")) { - sscanf( ld_line, "ORIGIN_TRI %d %d %d", &aiTransVtx[0], &aiTransVtx[1], &aiTransVtx[2]); // read given vertices + sscanf( ld_line, "ORIGIN_TRI %d %d %d", &aiTransVtx[0], &aiTransVtx[1], &aiTransVtx[2]); // read given vertices } - } + } File.Close(); CreateEmptyAttachingSounds(); } //---------------------------------------------------------------------------------------------- -void CEditModel::CreateMipModels_t(CObject3D &objRestFrame, CObject3D &objMipSourceFrame, - INDEX iVertexRemoveRate, INDEX iSurfacePreservingFactor) +void CEditModel::CreateMipModels_t(const ImportedMesh& baseMesh, INDEX iVertexRemoveRate, INDEX iSurfacePreservingFactor) { // free possible mip-models except main mip model INDEX iMipModel=1; for( ; iMipModelFillZBuffer( ZBUF_BACK); // get mip model ptr diff --git a/Sources/Engine/Models/EditModel.h b/Sources/Engine/Models/EditModel.h index b39023636..2eb5794fc 100644 --- a/Sources/Engine/Models/EditModel.h +++ b/Sources/Engine/Models/EditModel.h @@ -133,11 +133,11 @@ class ENGINE_API CEditModel : public CSerial struct FrameGenerator { CTString m_filename; - std::function m_generator; + std::function m_generator; }; - void NewModel(CObject3D *pO3D); // creates new model, surface, vertice and polygon arrays - void AddMipModel(CObject3D *pO3D); // adds one mip model + void NewModel(const ImportedMesh& mesh); // creates new model, surface, vertice and polygon arrays + void AddMipModel(const ImportedMesh& mesh); // adds one mip model // loads and converts model's animation data from script file std::vector LoadFrameGenerators(CAnimData& ad, CTStream* File, ImportedMesh& baseMesh, ImportedSkeleton& skeleton, const FLOATmatrix3D& mStretch); void LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMesh, ImportedSkeleton& skeleton, const FLOATmatrix3D &mStretch); // throw char * @@ -174,8 +174,7 @@ class ENGINE_API CEditModel : public CSerial void UpdateAnimations_t(CTFileName &fnScriptName); // throw char * // updates mip models configuration, looses their mapping ! void UpdateMipModels_t(CTFileName &fnScriptName); // throw char * - void CreateMipModels_t(CObject3D &objRestFrame, CObject3D &objMipSourceFrame, - INDEX iVertexRemoveRate, INDEX iSurfacePreservingFactor); + void CreateMipModels_t(const ImportedMesh& baseMesh, INDEX iVertexRemoveRate, INDEX iSurfacePreservingFactor); void DefaultMapping( INDEX iCurrentMip, INDEX iSurface=-1);// sets default mapping for given mip-model and surface (or all surfaces -1) void CalculateMapping( INDEX iCurrentMip, INDEX iSurfaceNo); // calculate mapping coordinates void CalculateMappingAll( INDEX iCurrentMip); diff --git a/Sources/Engine/Models/ImportedMesh.h b/Sources/Engine/Models/ImportedMesh.h index f1643685f..ce3faf293 100644 --- a/Sources/Engine/Models/ImportedMesh.h +++ b/Sources/Engine/Models/ImportedMesh.h @@ -38,6 +38,7 @@ struct ENGINE_API ImportedMesh ImportedMesh(const CTFileName& fileName, const FLOATmatrix3D& mTransform); ImportedMesh(const ImportedMesh&) = default; + void Clear(); void ApplySkinning(const ImportedSkeleton& baseSkeleton, const ImportedSkeleton& animSkeleton, const FLOATmatrix3D& mTransform); void FillFromFile(const CTFileName& fileName, const FLOATmatrix3D& mTransform); @@ -65,7 +66,6 @@ struct ENGINE_API ImportedMesh std::vector m_bonesNames; private: - void Clear(); void FillConversionArrays_t(const FLOATmatrix3D& mTransform, const aiScene* aiSceneMain); }; diff --git a/Sources/Engine/Models/MipMaker.cpp b/Sources/Engine/Models/MipMaker.cpp index e02d1e65b..240f8b9ec 100644 --- a/Sources/Engine/Models/MipMaker.cpp +++ b/Sources/Engine/Models/MipMaker.cpp @@ -68,33 +68,29 @@ void CMipPolygon::Clear() mp_pmpvFirstPolygonVertex = NULL; } -void CMipModel::ToObject3D( CObject3D &objDestination) +ImportedMesh CMipModel::GetMesh() { - // add one sector - CObjectSector *pOS = objDestination.ob_aoscSectors.New(1); + ImportedMesh mesh; // add vertices to sector - pOS->osc_aovxVertices.New( mm_amvVertices.Count()); - pOS->osc_aovxVertices.Lock(); + mesh.m_vertices.resize(mm_amvVertices.Count(), FLOAT3D(0, 0, 0)); INDEX iVertice = 0; FOREACHINDYNAMICARRAY( mm_amvVertices, CMipVertex, itVertice) { FLOAT3D vRestFrame = itVertice->mv_vRestFrameCoordinate; - pOS->osc_aovxVertices[ iVertice] = FLOATtoDOUBLE( vRestFrame); + mesh.m_vertices[ iVertice] = vRestFrame; iVertice++; } // add mip surfaces as materials to object 3d - pOS->osc_aomtMaterials.New( mm_amsSurfaces.Count()); - pOS->osc_aomtMaterials.Lock(); + mesh.m_materials.resize(mm_amsSurfaces.Count(), ImportedMesh::Material{}); INDEX iMaterial = 0; FOREACHINDYNAMICARRAY( mm_amsSurfaces, CMipSurface, itSurface) { - pOS->osc_aomtMaterials[ iMaterial].omt_Name = itSurface->ms_strName; - pOS->osc_aomtMaterials[ iMaterial].omt_Color = itSurface->ms_colColor; + mesh.m_materials[ iMaterial].cm_strName = itSurface->ms_strName; + mesh.m_materials[ iMaterial].cm_colColor = itSurface->ms_colColor; iMaterial ++; } - // add polygons to object 3d FOREACHINDYNAMICARRAY( mm_ampPolygons, CMipPolygon, itPolygon) { @@ -115,102 +111,96 @@ void CMipModel::ToObject3D( CObject3D &objDestination) ctPolygonVertices ++; } while( pmpvPolygonVertex != itPolygon->mp_pmpvFirstPolygonVertex); - // add current polygon - pOS->CreatePolygon( ctPolygonVertices, aivVertices, - pOS->osc_aomtMaterials[ itPolygon->mp_iSurface], 0, FALSE); + // add current polygon splitted to triangles + for (size_t i = 2; i < ctPolygonVertices; ++i) + { + ImportedMesh::Triangle triangle; + triangle.ct_iVtx[0] = aivVertices[0]; + triangle.ct_iVtx[1] = aivVertices[i - 1]; + triangle.ct_iVtx[2] = aivVertices[i]; + triangle.ct_iMaterial = itPolygon->mp_iSurface; + for (size_t uv = 0; uv < 3; ++uv) + for (size_t j = 0; j < 3; ++j) + triangle.ct_iTVtx[uv][j] = 0; + mesh.m_triangles.push_back(triangle); + } } - pOS->osc_aomtMaterials.Unlock(); - pOS->osc_aovxVertices.Unlock(); + for (size_t uv = 0; uv < 3; ++uv) + mesh.m_uvs[uv].push_back(FLOAT2D(0, 0)); + + return mesh; } -void CMipModel::FromObject3D_t( CObject3D &objRestFrame, CObject3D &objMipSourceFrame) +CMipModel::CMipModel(const ImportedMesh& mesh) { INDEX ctInvalidVertices = 0; CTString strInvalidVertices; char achrErrorVertice[ 256]; - objMipSourceFrame.ob_aoscSectors.Lock(); - objRestFrame.ob_aoscSectors.Lock(); - // lock object sectors dynamic array - objMipSourceFrame.ob_aoscSectors[0].LockAll(); - objRestFrame.ob_aoscSectors[0].LockAll(); - CObjectSector *pOS = &objMipSourceFrame.ob_aoscSectors[0]; // add mip surface - mm_amsSurfaces.New( pOS->osc_aomtMaterials.Count()); + mm_amsSurfaces.New(mesh.m_materials.size()); // copy material data from object 3d to mip surfaces INDEX iMaterial = 0; FOREACHINDYNAMICARRAY( mm_amsSurfaces, CMipSurface, itSurface) { - itSurface->ms_strName = pOS->osc_aomtMaterials[ iMaterial].omt_Name; - itSurface->ms_colColor = pOS->osc_aomtMaterials[ iMaterial].omt_Color; + itSurface->ms_strName =mesh.m_materials[iMaterial].cm_strName; + itSurface->ms_colColor =mesh.m_materials[iMaterial].cm_colColor; iMaterial ++; } // add mip vertices - mm_amvVertices.New( pOS->osc_aovxVertices.Count()); + mm_amvVertices.New(mesh.m_vertices.size()); // copy vertice coordinates from object3d to mip vertices INDEX iVertice = 0; {FOREACHINDYNAMICARRAY( mm_amvVertices, CMipVertex, itVertice) { - (FLOAT3D &)(*itVertice) = DOUBLEtoFLOAT( pOS->osc_aovxVertices[ iVertice]); - itVertice->mv_vRestFrameCoordinate = - DOUBLEtoFLOAT( objRestFrame.ob_aoscSectors[0].osc_aovxVertices[ iVertice]); + const FLOAT3D vertex = mesh.m_vertices[iVertice]; + (FLOAT3D &)(*itVertice) = vertex; + itVertice->mv_vRestFrameCoordinate = vertex; // calculate bounding box of all vertices mm_boxBoundingBox |= *itVertice; iVertice++; }} // add mip polygons - mm_ampPolygons.New( pOS->osc_aopoPolygons.Count()); + mm_ampPolygons.New(mesh.m_triangles.size()); // copy polygons object 3d to mip polygons INDEX iPolygon = 0; FOREACHINDYNAMICARRAY( mm_ampPolygons, CMipPolygon, itPolygon) { - CObjectPolygon &opoPolygon = pOS->osc_aopoPolygons[ iPolygon]; + const ImportedMesh::Triangle& triangle = mesh.m_triangles[iPolygon]; CMipPolygon &mpPolygon = itPolygon.Current(); - INDEX ctPolygonVertices = opoPolygon.opo_PolygonEdges.Count(); // allocate polygon vertices - CMipPolygonVertex *ppvPolygonVertices[ 32]; + CMipPolygonVertex *ppvPolygonVertices[3]; INDEX iPolygonVertice=0; - for( ; iPolygonVerticeosc_aovxVertices.Index( povxStart); + INDEX iVertexInSector = triangle.ct_iVtx[iPolygonVertice]; // set references to mip polygon and mip vertex ppvPolygonVertex->mpv_pmpPolygon = &mpPolygon; mm_amvVertices.Lock(); ppvPolygonVertex->mpv_pmvVertex = &mm_amvVertices[iVertexInSector]; mm_amvVertices.Unlock(); // link to previous and next vertices in the mip polygon - INDEX iNext=(iPolygonVertice+1)%ctPolygonVertices; + INDEX iNext=(iPolygonVertice+1)%3; ppvPolygonVertex->mpv_pmpvNextInPolygon = ppvPolygonVertices[ iNext]; } - opoPolygon.opo_PolygonEdges.Unlock(); // set first polygon vertex ptr and surface index to polygon itPolygon->mp_pmpvFirstPolygonVertex = ppvPolygonVertices[ 0]; - itPolygon->mp_iSurface = - pOS->osc_aomtMaterials.Index( opoPolygon.opo_Material); + itPolygon->mp_iSurface = triangle.ct_iMaterial; iPolygon++; } - objRestFrame.ob_aoscSectors[0].UnlockAll(); - // unlock all dynamic arrays in sector - objMipSourceFrame.ob_aoscSectors[0].UnlockAll(); - objRestFrame.ob_aoscSectors.Unlock(); - objMipSourceFrame.ob_aoscSectors.Unlock(); - if( ctInvalidVertices != 0) { sprintf( achrErrorVertice, diff --git a/Sources/Engine/Models/MipMaker.h b/Sources/Engine/Models/MipMaker.h index c8ddf5075..41eaeff2c 100644 --- a/Sources/Engine/Models/MipMaker.h +++ b/Sources/Engine/Models/MipMaker.h @@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif #include -#include +#include #include #include @@ -65,9 +65,9 @@ class CMipModel { CDynamicArray< CMipPolygon> mm_ampPolygons; CDynamicArray< CMipVertex> mm_amvVertices; FLOATaabbox3D mm_boxBoundingBox; - void FromObject3D_t( CObject3D &objRestFrame, CObject3D &objMipSourceFrame); - void ToObject3D( CObject3D &objDestination); - + ImportedMesh GetMesh(); + + explicit CMipModel(const ImportedMesh& mesh); ~CMipModel(); BOOL CreateMipModel_t(INDEX iVetexRemoveRate, INDEX iSurfacePreservingFactor); INDEX FindSurfacesForVertices(void); diff --git a/Sources/Modeler/ModelerView.cpp b/Sources/Modeler/ModelerView.cpp index 4dd4b8ea7..e0492f82a 100644 --- a/Sources/Modeler/ModelerView.cpp +++ b/Sources/Modeler/ModelerView.cpp @@ -3354,9 +3354,6 @@ void CModelerView::OnUpdateRecreateTexture(CCmdUI* pCmdUI) void CModelerView::OnCreateMipModels() { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); - CObject3D objRestFrame, objMipSourceFrame; - CListHead FrameNamesList; - CTFileName fnFrameFileName; char achrLine[ 128]; char achrBasePath[ PATH_MAX] = ""; char achrRestFrame[ PATH_MAX] = ""; @@ -3370,7 +3367,7 @@ void CModelerView::OnCreateMipModels() fnScriptName.RemoveApplicationPath_t(); // open script file CTFileStream File; - File.Open_t( fnScriptName); + File.Open_t( fnScriptName); FLOATmatrix3D mStretch; mStretch.Diagonal(1.0f); @@ -3415,24 +3412,6 @@ void CModelerView::OnCreateMipModels() &mTran(2,1), &mTran(2,2), &mTran(2,3), &mTran(3,1), &mTran(3,2), &mTran(3,3)); mStretch *= mTran; - } - else if( EQUAL_SUB_STR( "ANIM_START")) - { - pDoc->m_emEditModel.edm_md.LoadFromScript_t( &File, &FrameNamesList); - // extract file name of last rendered frame - INDEX iFrame = 0; - FOREACHINLIST( CFileNameNode, cfnn_Node, FrameNamesList, itFrameName) - { - if( m_iCurrentFrame == iFrame) - { - fnFrameFileName = CTString(itFrameName->cfnn_FileName); - break; - } - iFrame++; - } - // clear list of frames - FORDELETELIST( CFileNameNode, cfnn_Node, FrameNamesList, litDel) - delete &litDel.Current(); } } } @@ -3440,73 +3419,65 @@ void CModelerView::OnCreateMipModels() { (void) pstrError; } - // if frame name is extracted properly - if( fnFrameFileName != "") - { - // load rest frame - objRestFrame.FillFromMesh(ImportedMesh(CTString(achrRestFrameFullPath), mStretch)); - // load mip source frame - objMipSourceFrame.FillFromMesh(ImportedMesh(fnFrameFileName, mStretch)); - - // show progres dialog - CRect rectMainFrameSize; - CRect rectProgress, rectProgressNew; - pMainFrame->GetWindowRect( &rectMainFrameSize); - pMainFrame->m_NewProgress.Create( IDD_NEW_PROGRESS, pMainFrame); - pMainFrame->m_NewProgress.GetWindowRect( &rectProgress); - rectProgressNew.left = rectMainFrameSize.Width()/2 - rectProgress.Width()/2; - rectProgressNew.top = rectMainFrameSize.Height()/2 - rectProgress.Height()/2; - rectProgressNew.right = rectProgressNew.left + rectProgress.Width(); - rectProgressNew.bottom = rectProgressNew.top + rectProgress.Height(); - pMainFrame->m_NewProgress.MoveWindow( rectProgressNew); - pMainFrame->m_NewProgress.ShowWindow(SW_SHOW); - CDlgAutoMipModeling dlgAutoMipModeling; - if( (dlgAutoMipModeling.DoModal() != IDOK) || - (dlgAutoMipModeling.m_iVerticesToRemove<=0) || - (dlgAutoMipModeling.m_iSurfacePreservingFactor<1) || - (dlgAutoMipModeling.m_iSurfacePreservingFactor>99) ) - { - pMainFrame->m_NewProgress.DestroyWindow(); - return; - } - // create mip models - pDoc->m_emEditModel.CreateMipModels_t( objRestFrame, objMipSourceFrame, - dlgAutoMipModeling.m_iVerticesToRemove, dlgAutoMipModeling.m_iSurfacePreservingFactor); - // copy mapping from main mip model - pDoc->m_emEditModel.SaveMapping_t( CTString("Temp\\ForAutoMipMapping.map"), 0); - // paste mapping over all smaller mip models - INDEX iMipModel=1; - for( ; iMipModelm_emEditModel.edm_md.md_MipCt; iMipModel++) - { - pDoc->m_emEditModel.LoadMapping_t( CTString("Temp\\ForAutoMipMapping.map"), iMipModel); - } + // show progres dialog + CRect rectMainFrameSize; + CRect rectProgress, rectProgressNew; + pMainFrame->GetWindowRect( &rectMainFrameSize); + pMainFrame->m_NewProgress.Create( IDD_NEW_PROGRESS, pMainFrame); + pMainFrame->m_NewProgress.GetWindowRect( &rectProgress); + rectProgressNew.left = rectMainFrameSize.Width()/2 - rectProgress.Width()/2; + rectProgressNew.top = rectMainFrameSize.Height()/2 - rectProgress.Height()/2; + rectProgressNew.right = rectProgressNew.left + rectProgress.Width(); + rectProgressNew.bottom = rectProgressNew.top + rectProgress.Height(); + pMainFrame->m_NewProgress.MoveWindow( rectProgressNew); + pMainFrame->m_NewProgress.ShowWindow(SW_SHOW); - for( INDEX iSurface=1; - iSurfacem_emEditModel.edm_md.md_MipInfos[0].mmpi_MappingSurfaces.Count(); - iSurface++) + CDlgAutoMipModeling dlgAutoMipModeling; + if( (dlgAutoMipModeling.DoModal() != IDOK) || + (dlgAutoMipModeling.m_iVerticesToRemove<=0) || + (dlgAutoMipModeling.m_iSurfacePreservingFactor<1) || + (dlgAutoMipModeling.m_iSurfacePreservingFactor>99) ) + { + pMainFrame->m_NewProgress.DestroyWindow(); + return; + } + // create mip models + pDoc->m_emEditModel.CreateMipModels_t(ImportedMesh(CTString(achrRestFrameFullPath), mStretch), + dlgAutoMipModeling.m_iVerticesToRemove, dlgAutoMipModeling.m_iSurfacePreservingFactor); + // copy mapping from main mip model + pDoc->m_emEditModel.SaveMapping_t( CTString("Temp\\ForAutoMipMapping.map"), 0); + // paste mapping over all smaller mip models + INDEX iMipModel=1; + for( ; iMipModelm_emEditModel.edm_md.md_MipCt; iMipModel++) + { + pDoc->m_emEditModel.LoadMapping_t( CTString("Temp\\ForAutoMipMapping.map"), iMipModel); + } + + for( INDEX iSurface=1; + iSurfacem_emEditModel.edm_md.md_MipInfos[0].mmpi_MappingSurfaces.Count(); + iSurface++) + { + // get rendering flags from main mip model for current surface + ULONG ulRenderFlags; + enum SurfaceShadingType sstShading; + enum SurfaceTranslucencyType sttTranslucency; + m_ModelObject.GetSurfaceRenderFlags( 0, iSurface, sstShading, sttTranslucency, ulRenderFlags); + // get color of surface + UBYTE ubSurfaceTransparency = (UBYTE) (m_ModelObject.GetSurfaceColor( 0, iSurface) & CT_OPAQUE); + for( iMipModel=1; iMipModelm_emEditModel.edm_md.md_MipCt; iMipModel++) { - // get rendering flags from main mip model for current surface - ULONG ulRenderFlags; - enum SurfaceShadingType sstShading; - enum SurfaceTranslucencyType sttTranslucency; - m_ModelObject.GetSurfaceRenderFlags( 0, iSurface, sstShading, sttTranslucency, ulRenderFlags); - // get color of surface - UBYTE ubSurfaceTransparency = (UBYTE) (m_ModelObject.GetSurfaceColor( 0, iSurface) & CT_OPAQUE); - for( iMipModel=1; iMipModelm_emEditModel.edm_md.md_MipCt; iMipModel++) - { - // set render flags - m_ModelObject.SetSurfaceRenderFlags( iMipModel, iSurface, sstShading, sttTranslucency, ulRenderFlags); - COLOR colSurfaceColor = m_ModelObject.GetSurfaceColor( iMipModel, iSurface); - // set remembered transparency - colSurfaceColor = (colSurfaceColor & 0xFFFFFF00) | ubSurfaceTransparency; - // set new surface color - m_ModelObject.SetSurfaceColor( iMipModel, iSurface, colSurfaceColor); - } + // set render flags + m_ModelObject.SetSurfaceRenderFlags( iMipModel, iSurface, sstShading, sttTranslucency, ulRenderFlags); + COLOR colSurfaceColor = m_ModelObject.GetSurfaceColor( iMipModel, iSurface); + // set remembered transparency + colSurfaceColor = (colSurfaceColor & 0xFFFFFF00) | ubSurfaceTransparency; + // set new surface color + m_ModelObject.SetSurfaceColor( iMipModel, iSurface, colSurfaceColor); } - // destroy progres window - pMainFrame->m_NewProgress.DestroyWindow(); } + // destroy progres window + pMainFrame->m_NewProgress.DestroyWindow(); } catch( char *pStrError) { From 7fa9f08733736d943391d82b85e854dce491eeb2 Mon Sep 17 00:00:00 2001 From: SeriousAlexej Date: Mon, 15 Nov 2021 15:01:08 +0200 Subject: [PATCH 3/5] Fix random typo --- Sources/Engine/Models/EditModel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Engine/Models/EditModel.cpp b/Sources/Engine/Models/EditModel.cpp index c439c66c1..4e2c57cbd 100644 --- a/Sources/Engine/Models/EditModel.cpp +++ b/Sources/Engine/Models/EditModel.cpp @@ -546,8 +546,7 @@ void CEditModel::LoadModelAnimationData_t( CTStream *pFile, ImportedMesh& baseMe vVtx *= mOrientation; } OneFrameBB |= FLOATaabbox3D(vVtx); - avVertices.emplace_back(); - avVertices.back() = vVtx; // cache vertex + avVertices.emplace_back(vVtx); } // remember this frame's Bounding Box edm_md.md_FrameInfos[iO3D].mfi_Box = OneFrameBB; From dd4fadcc75d92a1b1a30e573b11741a20eecc1ea Mon Sep 17 00:00:00 2001 From: SeriousAlexej Date: Mon, 15 Nov 2021 15:06:35 +0200 Subject: [PATCH 4/5] Do not affect bone triangles with stretch factor --- Sources/Engine/Models/EditModel.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Engine/Models/EditModel.cpp b/Sources/Engine/Models/EditModel.cpp index 4e2c57cbd..bf992bcc5 100644 --- a/Sources/Engine/Models/EditModel.cpp +++ b/Sources/Engine/Models/EditModel.cpp @@ -114,7 +114,7 @@ CProgressRoutines::CProgressRoutines() SetProgressState = NULL; } -void CreateBoneTriangles(ImportedMesh& mesh, const ImportedSkeleton& skeleton, const FLOATmatrix3D& transform) +void CreateBoneTriangles(ImportedMesh& mesh, const ImportedSkeleton& skeleton, const FLOATmatrix3D& transform, FLOAT stretch) { size_t materialIndex = -1; for (size_t boneIndex = 0; boneIndex < mesh.m_bonesNames.size(); ++boneIndex) @@ -127,8 +127,8 @@ void CreateBoneTriangles(ImportedMesh& mesh, const ImportedSkeleton& skeleton, c const FLOATmatrix4D boneTransform = bone.GetAbsoluteTransform(); FLOAT4D v0(0.0f, 0.0f, 0.0f, 1.0f); - FLOAT4D v1(0.0f, 0.25f, 0.0f, 1.0f); - FLOAT4D v2(0.0f, 0.0f, -0.25f, 1.0f); + FLOAT4D v1(0.0f, 0.25f / stretch, 0.0f, 1.0f); + FLOAT4D v2(0.0f, 0.0f, -0.25f / stretch, 1.0f); v0 = v0 * boneTransform; v1 = v1 * boneTransform; v2 = v2 * boneTransform; @@ -1307,6 +1307,7 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * bMappingDimFound = FALSE; bAnimationsFound = FALSE; bLoadInitialMapping = FALSE; + FLOAT fStretch = 1.0f; FOREVER { @@ -1330,7 +1331,6 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * else if( EQUAL_SUB_STR( "SIZE")) { _strupr( ld_line); - FLOAT fStretch = 1.0f; sscanf( ld_line, "SIZE %g", &fStretch); mStretch *= fStretch; } @@ -1432,7 +1432,7 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * if (baseMesh.m_vertices.empty()) { if (allowedToCreateBoneTriangles && hasSkeletalAnimation && !hasRegularAnimation) - CreateBoneTriangles(mesh, skeleton, mStretch); + CreateBoneTriangles(mesh, skeleton, mStretch, fStretch); baseMesh = mesh; } // If there are no vertices in model, call New Model and calculate UV mapping From b411c24d8cfa5b5cc15d5fe2899dee35836c6398 Mon Sep 17 00:00:00 2001 From: SeriousAlexej Date: Mon, 15 Nov 2021 17:03:10 +0200 Subject: [PATCH 5/5] Fix broken UV map in mip models --- Sources/Engine/Models/EditModel.cpp | 89 +---------------------------- Sources/Engine/Models/EditModel.h | 36 +----------- Sources/Engine/Models/MipMaker.cpp | 31 +++++++--- Sources/Engine/Models/MipMaker.h | 1 + 4 files changed, 29 insertions(+), 128 deletions(-) diff --git a/Sources/Engine/Models/EditModel.cpp b/Sources/Engine/Models/EditModel.cpp index bf992bcc5..d684324b1 100644 --- a/Sources/Engine/Models/EditModel.cpp +++ b/Sources/Engine/Models/EditModel.cpp @@ -1526,8 +1526,6 @@ void CEditModel::LoadFromScript_t(CTFileName &fnScriptName) // throw char * (void)strError; } - CalculateMappingForMips(); - File.Close(); if( edm_aasAttachedSounds.Count() == 0) @@ -1656,6 +1654,7 @@ void CEditModel::AddMipModel(const ImportedMesh& mesh) ms.ms_ulRenderingFlags = SRF_DIFFUSE|SRF_NEW_TEXTURE_FORMAT; } + struct VertexRemap { FLOAT2D uv; @@ -1687,7 +1686,6 @@ void CEditModel::AddMipModel(const ImportedMesh& mesh) for (size_t e = 0; e < 3; ++e) { FLOAT2D vtxUV(mesh.m_uvs[0][triangle.ct_iTVtx[0][e]]); - vtxUV(2) *= -1.0f; VertexRemap vertex_remap{ vtxUV, triangle.ct_iMaterial, triangle.ct_iVtx[e] }; auto found_pos = uniqueTexCoords.find(vertex_remap); @@ -1713,7 +1711,7 @@ void CEditModel::AddMipModel(const ImportedMesh& mesh) uv_coord(1) *= edm_md.md_Width / 1024.0f; uv_coord(2) *= edm_md.md_Height / 1024.0f; - pmmpi->mmpi_TextureVertices[i].mtv_UVW = FLOAT3D(uv_coord(1), -uv_coord(2), 0.0f); + pmmpi->mmpi_TextureVertices[i].mtv_UVW = FLOAT3D(uv_coord(1), uv_coord(2), 0.0f); MEX2D mexUV; mexUV(1) = MEX_METERS(pmmpi->mmpi_TextureVertices[i].mtv_UVW(1)); mexUV(2) = MEX_METERS(pmmpi->mmpi_TextureVertices[i].mtv_UVW(2)); @@ -1753,88 +1751,6 @@ void CEditModel::AddMipModel(const ImportedMesh& mesh) edm_md.md_MipCt ++; // finally, this mip-model is done. } -//---------------------------------------------------------------------------------------------- -/* - * Routine calculate mapping for mip models (except for main mip) - */ -void CEditModel::CalculateMappingForMips( void) -{ - // for each mip model except first - for( INDEX iCurMip = 1; iCurMip< edm_md.md_MipCt; iCurMip++) - { - // get current mip model - struct ModelMipInfo *pMMICur = &edm_md.md_MipInfos[ iCurMip]; - // get previous mip model - struct ModelMipInfo *pMMIPrev = &edm_md.md_MipInfos[ iCurMip-1]; - // for each surface in current mip model - for( INDEX iSurfaceCur = 0; iSurfaceCur < pMMICur->mmpi_MappingSurfaces.Count(); iSurfaceCur++) - { - MappingSurface *pmsSurfCur = &pMMICur->mmpi_MappingSurfaces[iSurfaceCur]; - // for each texture vertex in surface - for(INDEX iSurfCurTV=0; iSurfCurTVms_aiTextureVertices.Count(); iSurfCurTV++) - { - INDEX iCurGlobalTV = pmsSurfCur->ms_aiTextureVertices[iSurfCurTV]; - ModelTextureVertex *pmtvCur = &pMMICur->mmpi_TextureVertices[iCurGlobalTV]; - // obtain index of model vertex - INDEX iCurMV = pmtvCur->mtv_iTransformedVertex; - - // get 3D coordinate of vertex from main mip - FLOAT3D vMainMipCoordCur = edm_md.md_MainMipVertices[ iCurMV]; - - // -------- Find closest vertex (using 3D coordinate) in previous mip - - // in previous mip model find surface with same name - MappingSurface *pmsSurfPrev = NULL; - for( INDEX iSurfacePrev = 0; iSurfacePrev < pMMIPrev->mmpi_MappingSurfaces.Count(); iSurfacePrev++) - { - pmsSurfPrev = &pMMIPrev->mmpi_MappingSurfaces[iSurfacePrev]; - if( pmsSurfCur->ms_Name == pmsSurfPrev->ms_Name) - { - break; - } - } - - // new surfaces can't appear - ASSERT(pmsSurfPrev != NULL); - if( pmsSurfPrev == NULL) - { - WarningMessage( "Mip model %d has surface that does not exist in previous mip. That is not allowed.", iCurMip); - break; - } - - // set hudge distance as current minimum - FLOAT fMinDistance = 99999999.0f; - ModelTextureVertex *pmtvClosestPrev = NULL; - - // for each texture vertex in previous mip's surface with same name - for(INDEX iSurfPrevTV=0; iSurfPrevTVms_aiTextureVertices.Count(); iSurfPrevTV++) - { - INDEX iPrevGlobalTV = pmsSurfPrev->ms_aiTextureVertices[iSurfPrevTV]; - ModelTextureVertex *pmtvPrev = &pMMIPrev->mmpi_TextureVertices[iPrevGlobalTV]; - // obtain index of model vertex - INDEX iPrevMV = pmtvPrev->mtv_iTransformedVertex; - // get 3D coordinate of vertex from main mip - FLOAT3D vMainMipCoordPrev = edm_md.md_MainMipVertices[ iPrevMV]; - // get distance of these two vertices - FLOAT fAbsoluteDistance = Abs( (vMainMipCoordPrev - vMainMipCoordCur).Length()); - if( fAbsoluteDistance < fMinDistance) - { - // remember current texture vertex as closest one - fMinDistance = fAbsoluteDistance; - pmtvClosestPrev = pmtvPrev; - } - } - ASSERT( pmtvClosestPrev != NULL); - // copy mapping coordinates from closest mapping vertex in previous mip - pmtvCur->mtv_UVW = pmtvClosestPrev->mtv_UVW; - pmtvCur->mtv_UV = pmtvClosestPrev->mtv_UV; - pmtvCur->mtv_vU = pmtvClosestPrev->mtv_vU; - pmtvCur->mtv_vV = pmtvClosestPrev->mtv_vV; - } - } - } -} - /* * This routine opens last script file loaded, repeats reading key-words until it finds * key-word "ANIM_START". Then it calls animation data load from script routine. @@ -1957,7 +1873,6 @@ void CEditModel::CreateMipModels_t(const ImportedMesh& baseMesh, INDEX iVertexRe ProgresRoutines.SetProgressState(ctVerticesInRestFrame); edm_md.SpreadMipSwitchFactors( 0, 5.0f); edm_md.LinkDataForSurfaces(FALSE); - CalculateMappingForMips(); } //---------------------------------------------------------------------------------------------- /* diff --git a/Sources/Engine/Models/EditModel.h b/Sources/Engine/Models/EditModel.h index 2eb5794fc..a1ee4979d 100644 --- a/Sources/Engine/Models/EditModel.h +++ b/Sources/Engine/Models/EditModel.h @@ -161,23 +161,12 @@ class ENGINE_API CEditModel : public CSerial // creates default script file void CreateScriptFile_t(CTFileName &fnFile); // throw char * // creates mip-model and mapping default constructios after it loads data from script - void LoadFromScript_t(CTFileName &fnFileName); // throw char * - // recalculate mapping for surface after some polygon has been added to surface - void RecalculateSurfaceMapping( INDEX iMipModel, INDEX iSurface); - // functions for extracting texture vertex links for given mip model - void CalculateSurfaceCenterOffset( INDEX iCurrentMip, INDEX iSurface); - void RemapTextureVerticesForSurface(INDEX iMip, INDEX iSurface, BOOL bJustCount); - void RemapTextureVertices( INDEX iCurrentMip); - // calculates mapping for mip models (except for main mip) - void CalculateMappingForMips(void); + void LoadFromScript_t(CTFileName &fnFileName); // throw char * // updates animations void UpdateAnimations_t(CTFileName &fnScriptName); // throw char * // updates mip models configuration, looses their mapping ! - void UpdateMipModels_t(CTFileName &fnScriptName); // throw char * + void UpdateMipModels_t(CTFileName &fnScriptName); // throw char * void CreateMipModels_t(const ImportedMesh& baseMesh, INDEX iVertexRemoveRate, INDEX iSurfacePreservingFactor); - void DefaultMapping( INDEX iCurrentMip, INDEX iSurface=-1);// sets default mapping for given mip-model and surface (or all surfaces -1) - void CalculateMapping( INDEX iCurrentMip, INDEX iSurfaceNo); // calculate mapping coordinates - void CalculateMappingAll( INDEX iCurrentMip); void DrawWireSurface( CDrawPort *pDP, INDEX iCurrentMip, INDEX iCurrentSurface, FLOAT fMagnifyFactor, PIX offx, PIX offy, COLOR clrVisible, COLOR clrInvisible); // draws given surface in wire frame void DrawFilledSurface( CDrawPort *pDP, INDEX iCurrentMip, INDEX iCurrentSurface, @@ -185,31 +174,10 @@ class ENGINE_API CEditModel : public CSerial void PrintSurfaceNumbers( CDrawPort *pDP, CFontData *pFont, INDEX iCurrentMip, FLOAT fMagnifyFactor, PIX offx, PIX offy, COLOR clrInk); // prints surface numbers void ExportSurfaceNumbersAndNames( CTFileName fnFile); - void GetScreenSurfaceCenter( CDrawPort *pDP, INDEX iCurrentMip, - INDEX iCurrentSurface, FLOAT fMagnifyFactor, PIX offx, PIX offy, - PIX &XCenter, PIX &YCenter); // Calculates given surface's center point in view's window (in pixels) - FLOATaabbox3D CalculateSurfaceBBox( INDEX iCurrentMip, // used to calculate mapping coordinate's bbox - INDEX iSurfaceNo, FLOAT3D f3Position, FLOAT3D f3Angle, FLOAT fZoom); - void CalculateMapping(); // used to calculate mapping coordinates - BOOL ChangeSurfacePositionRelative( INDEX iCurrentMip, INDEX iCurrentSurface, FLOAT fDZoom, - FLOAT dX, FLOAT dY, PIX dTH, PIX dTV); // if it can, sets surface position with given offseted values - BOOL ChangeSurfacePositionAbsolute( INDEX iCurrentMip, INDEX iCurrentSurface, - FLOAT newZoom, FLOAT3D newCenter, FLOAT3D newAngle); // if it can, sets surface position to given values - void RememberSurfaceUndo( INDEX iCurrentMip, INDEX iCurrentSurface); // remember undo position - ModelTextureVertex *FindClosestMappingVertex( INDEX iCurrentMip, INDEX iCurrentSurface, - PIX ptx, PIX pty, FLOAT fMagnifyFactor, PIX offx, PIX offy);// finds closest point and returns it - void MoveVertex( ModelTextureVertex *pmtvClosestVertex, PIX dx, PIX dy, INDEX iCurrentMip, INDEX iCurrentSurface); // try new vertex position - void RememberVertexUndo( ModelTextureVertex *pmtvClosestVertex);// remember coordinate change into undo buffer // add one texture to list of working textures CTextureDataInfo *AddTexture_t(const CTFileName &fnFileName, const MEX mexWidth, const MEX mexHeight); // throw char * - FLOAT3D GetSurfacePos(INDEX iCurrentMip, INDEX iCurrentSurface); // Retrieves given surface's position - FLOAT3D GetSurfaceAngles(INDEX iCurrentMip, INDEX iCurrentSurface); // Retrieves given surface's angles - FLOAT GetSurfaceZoom(INDEX iCurrentMip, INDEX iCurrentSurface); // Retrieves given surface's zoom factor const char *GetSurfaceName(INDEX iCurrentMip, INDEX iCurrentSurface); // Retrieves given surface's name - void Undo(void); // Undoes last operation - void Redo(void); // Redoes last operation - void RemoveTexture(char *pFileName); // removes one of working textures in modeler app void MovePatchRelative( INDEX iMaskBit, MEX2D mexOffset); void SetPatchStretch( INDEX iMaskBit, FLOAT fNewStretch); BOOL EditAddPatch( CTFileName fnPatchName, MEX2D mexPos, INDEX &iMaskBit); // Adds one patch diff --git a/Sources/Engine/Models/MipMaker.cpp b/Sources/Engine/Models/MipMaker.cpp index 240f8b9ec..f7e63a10a 100644 --- a/Sources/Engine/Models/MipMaker.cpp +++ b/Sources/Engine/Models/MipMaker.cpp @@ -23,10 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +#include + // if vertex removing should occure only inside surfaces static BOOL _bPreserveSurfaces; - CMipModel::~CMipModel() { mm_amsSurfaces.Clear(); @@ -91,11 +92,14 @@ ImportedMesh CMipModel::GetMesh() iMaterial ++; } + std::unordered_map texCoordsRemap; + // add polygons to object 3d FOREACHINDYNAMICARRAY( mm_ampPolygons, CMipPolygon, itPolygon) { // prepare array of polygon vertex indices - INDEX aivVertices[ 32]; + INDEX aivVertices[32]; + INDEX texCoords[32]; CMipPolygonVertex *pmpvPolygonVertex = itPolygon->mp_pmpvFirstPolygonVertex; INDEX ctPolygonVertices = 0; do @@ -103,6 +107,20 @@ ImportedMesh CMipModel::GetMesh() ASSERT( ctPolygonVertices<32); if( ctPolygonVertices >= 32) break; // add global index of vertex to list of vertex indices of polygon + INDEX texCoordIndex; + FLOAT2D vtxUV = pmpvPolygonVertex->m_uv; + auto foundPos = texCoordsRemap.find(vtxUV); + if (foundPos != texCoordsRemap.end()) + { + texCoordIndex = foundPos->second; + } + else + { + texCoordIndex = mesh.m_uvs[0].size(); + mesh.m_uvs[0].push_back(vtxUV); + texCoordsRemap[vtxUV] = texCoordIndex; + } + texCoords[ctPolygonVertices] = texCoordIndex; mm_amvVertices.Lock(); aivVertices[ ctPolygonVertices] = mm_amvVertices.Index( pmpvPolygonVertex->mpv_pmvVertex); @@ -118,15 +136,13 @@ ImportedMesh CMipModel::GetMesh() triangle.ct_iVtx[0] = aivVertices[0]; triangle.ct_iVtx[1] = aivVertices[i - 1]; triangle.ct_iVtx[2] = aivVertices[i]; + triangle.ct_iTVtx[0][0] = texCoords[0]; + triangle.ct_iTVtx[0][1] = texCoords[i - 1]; + triangle.ct_iTVtx[0][2] = texCoords[i]; triangle.ct_iMaterial = itPolygon->mp_iSurface; - for (size_t uv = 0; uv < 3; ++uv) - for (size_t j = 0; j < 3; ++j) - triangle.ct_iTVtx[uv][j] = 0; mesh.m_triangles.push_back(triangle); } } - for (size_t uv = 0; uv < 3; ++uv) - mesh.m_uvs[uv].push_back(FLOAT2D(0, 0)); return mesh; } @@ -187,6 +203,7 @@ CMipModel::CMipModel(const ImportedMesh& mesh) INDEX iVertexInSector = triangle.ct_iVtx[iPolygonVertice]; // set references to mip polygon and mip vertex ppvPolygonVertex->mpv_pmpPolygon = &mpPolygon; + ppvPolygonVertex->m_uv = mesh.m_uvs[0][triangle.ct_iTVtx[0][iPolygonVertice]]; mm_amvVertices.Lock(); ppvPolygonVertex->mpv_pmvVertex = &mm_amvVertices[iVertexInSector]; mm_amvVertices.Unlock(); diff --git a/Sources/Engine/Models/MipMaker.h b/Sources/Engine/Models/MipMaker.h index 41eaeff2c..5281e8486 100644 --- a/Sources/Engine/Models/MipMaker.h +++ b/Sources/Engine/Models/MipMaker.h @@ -29,6 +29,7 @@ class CMipPolygonVertex { CMipPolygonVertex *mpv_pmpvNextInPolygon; class CMipPolygon *mpv_pmpPolygon; class CMipVertex *mpv_pmvVertex; + FLOAT2D m_uv; inline void Clear(void) {}; };