88using ContentEditor . Editor ;
99using ContentPatcher ;
1010using ReeLib ;
11+ using ReeLib . Common ;
1112using ReeLib . via ;
1213
1314namespace ContentEditor . App ;
@@ -145,7 +146,7 @@ public void ChangeMesh(FileHandle newHandle)
145146 ChangeMesh ( ) ;
146147 }
147148
148- private void ChangeMesh ( )
149+ private void ChangeMesh ( bool resetMdf = true )
149150 {
150151 meshPath = Handle . Filepath ;
151152 if ( ! Handle . References . Contains ( this ) ) Handle . References . Add ( this ) ;
@@ -156,11 +157,19 @@ private void ChangeMesh()
156157 }
157158 return ;
158159 }
159- TryGuessMdfFilepath ( ) ;
160+ if ( resetMdf ) TryGuessMdfFilepath ( ) ;
160161
161162 var meshComponent = previewGameobject ? . GetComponent < MeshComponent > ( ) ;
162- meshComponent ? . Transform . InvalidateTransform ( ) ;
163- meshComponent ? . SetMesh ( Handle , Handle ) ;
163+ if ( meshComponent != null ) {
164+
165+ meshComponent . Transform . InvalidateTransform ( ) ;
166+ if ( ! string . IsNullOrEmpty ( mdfSource ) ) {
167+ isMDFUpdateRequest = true ;
168+ UpdateMaterial ( meshComponent ) ;
169+ } else {
170+ meshComponent . SetMesh ( Handle , Handle ) ;
171+ }
172+ }
164173 if ( mesh . HasAnimations && string . IsNullOrEmpty ( animationSourceFile ) ) {
165174 animationSourceFile = Handle . Filepath ;
166175 }
@@ -310,6 +319,12 @@ private bool ShowMenu(MeshComponent meshComponent)
310319 ImguiHelpers . VerticalSeparator ( ) ;
311320 if ( ImGui . MenuItem ( $ "{ AppIcons . SI_MeshViewerMeshGroup } Mesh Groups") ) ImGui . OpenPopup ( "MeshGroups" ) ;
312321 if ( ImGui . MenuItem ( $ "{ AppIcons . SI_FileType_MDF } Material") ) ImGui . OpenPopup ( "Material" ) ;
322+ var mdfErrors = GetMdfErrors ( ) ;
323+ if ( mdfErrors != null ) {
324+ using var _ = ImguiHelpers . OverrideStyleCol ( ImGuiCol . Text , Colors . Warning ) ;
325+ ImGui . MenuItem ( $ "{ AppIcons . SI_GenericWarning } ") ;
326+ ImguiHelpers . Tooltip ( mdfErrors ) ;
327+ }
313328 if ( ImGui . BeginMenu ( $ "{ AppIcons . SI_FileType_RCOL } RCOL") ) {
314329 var rcolEdit = Scene ! . Root . SetEditMode ( previewGameobject . GetOrAddComponent < RequestSetColliderComponent > ( ) ) ;
315330 rcolEdit ? . DrawMainUI ( ) ;
@@ -398,6 +413,26 @@ private void ShowMeshInfo()
398413 }
399414 }
400415
416+ private string ? GetMdfErrors ( )
417+ {
418+ var meshComponent = previewGameobject ? . GetComponent < MeshComponent > ( ) ;
419+ if ( meshComponent ? . MeshHandle == null || mesh == null || string . IsNullOrEmpty ( mdfSource ) ) return null ;
420+
421+ if ( mesh != null && meshComponent . MeshHandle ? . Material != null ) {
422+ var mdfMats = meshComponent . MeshHandle . Material . Materials ;
423+ var matNames = mesh . NativeMesh . MaterialNames ;
424+ var nameMismatch = matNames . Any ( name => ! mdfMats . Select ( m => m . name ) . Contains ( name ) ) ;
425+ if ( mdfMats . Count != mesh . NativeMesh . MaterialNames . Count ) {
426+ return "Mesh material count does not match MDF2 material count. Textures won't display correctly ingame.\n Ensure that both counts match." ;
427+ }
428+ if ( nameMismatch ) {
429+ return "Mesh references material names that are not present in the selected MDF2." ;
430+ }
431+ }
432+
433+ return null ;
434+ }
435+
401436 private void ShowMaterialSettings ( MeshComponent meshComponent )
402437 {
403438 bool useHighRes = textureMode == TextureMode . HighRes ;
@@ -422,6 +457,69 @@ private void ShowMaterialSettings(MeshComponent meshComponent)
422457 ( v , p ) => v . mdfSource = p ?? "" ) ;
423458 }
424459 mdfPickerContext . ShowUI ( ) ;
460+ if ( mesh != null && meshComponent . MeshHandle ? . Material != null ) {
461+ var mdfMats = meshComponent . MeshHandle . Material . Materials ;
462+ var matNames = mesh . NativeMesh . MaterialNames ;
463+ var nameMismatch = matNames . Any ( name => ! mdfMats . Select ( m => m . name ) . Contains ( name ) ) ;
464+ var error = GetMdfErrors ( ) ;
465+ if ( error != null ) {
466+ ImGui . TextColored ( Colors . Warning , error ) ;
467+ }
468+
469+ if ( mesh . NativeMesh . MaterialNames . Count < mdfMats . Count && ! string . IsNullOrEmpty ( mdfSource ) ) {
470+ if ( ImGui . Button ( "Add missing materials from selected MDF2" ) ) {
471+ AlignMatNamesToMdf ( ) ;
472+ }
473+ }
474+
475+ ImGui . SeparatorText ( "Material mapping" ) ;
476+ for ( int i = 0 ; i < mesh . NativeMesh . MaterialNames . Count ; i ++ ) {
477+ var matName = mesh . NativeMesh . MaterialNames [ i ] ;
478+ if ( ImGui . Button ( $ "{ AppIcons . SI_GenericDelete } ##{ i } ") ) {
479+ var i_backup = i -- ;
480+ UndoRedo . RecordCallback ( null , ( ) => matNames . RemoveAt ( i_backup ) , ( ) => matNames . Insert ( i_backup , matName ) ) ;
481+ UndoRedo . AttachCallbackToLastAction ( UndoRedo . CallbackType . Both , ApplyMeshChanges ) ;
482+ continue ;
483+ }
484+ ImGui . SameLine ( ) ;
485+ ImGui . Text ( i . ToString ( ) ) ;
486+ ImGui . SameLine ( ) ;
487+ if ( ImGui . InputText ( $ "##{ i } ", ref matName , 48 ) ) {
488+ var prevName = mesh . NativeMesh . MaterialNames [ i ] ;
489+ int i_backup = i ;
490+ UndoRedo . RecordCallbackSetter ( null , mesh . NativeMesh . MaterialNames , prevName , matName , ( o , v ) => o [ i_backup ] = v , $ "MatName{ i } _{ Handle . Filepath } ") ;
491+ UndoRedo . AttachCallbackToLastAction ( UndoRedo . CallbackType . Both , ApplyMeshChanges ) ;
492+ }
493+ }
494+ if ( ImGui . Button ( $ "{ AppIcons . SI_GenericAdd } ") ) {
495+ var newName = "NewMaterial" . GetUniqueName ( s => matNames . Contains ( s ) ) ;
496+ UndoRedo . RecordCallback ( null , ( ) => matNames . Add ( newName ) , ( ) => matNames . Remove ( newName ) ) ;
497+ UndoRedo . AttachCallbackToLastAction ( UndoRedo . CallbackType . Both , ApplyMeshChanges ) ;
498+ }
499+ }
500+ }
501+
502+ private void ApplyMeshChanges ( )
503+ {
504+ Handle . Modified = true ;
505+ ChangeMesh ( false ) ;
506+ }
507+
508+ private void AlignMatNamesToMdf ( )
509+ {
510+ var meshComponent = previewGameobject ? . GetComponent < MeshComponent > ( ) ;
511+ if ( meshComponent ? . MeshHandle == null || mesh == null ) return ;
512+
513+ var mdfMats = meshComponent . MeshHandle . Material . Materials ;
514+ var matNames = mesh . NativeMesh . MaterialNames ;
515+ if ( matNames . Count < mdfMats . Count ) {
516+ var missingMats = mdfMats . Select ( m => m . name ) . Where ( m => ! matNames . Contains ( m ) ) ;
517+ foreach ( var mat in missingMats ) {
518+ if ( matNames . Count >= mdfMats . Count ) break ;
519+ matNames . Add ( mat ) ;
520+ }
521+ }
522+ Handle . Modified = true ;
425523 }
426524
427525 private void ShowImportExportMenu ( )
@@ -477,6 +575,7 @@ private void ShowImportExportMenu()
477575 Handle . Revert ( Workspace ) ;
478576 Handle . Modified = true ;
479577 ChangeMesh ( ) ;
578+ AlignMatNamesToMdf ( ) ;
480579 }
481580 } ) ;
482581 } , lastImportSourcePath , fileExtension : FileFilters . MeshFilesAll ) ;
0 commit comments