You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3229490 on 2016/12/09 by Cody.Albert Integrated fix to support named changelists in SVN Change 3229574 on 2016/12/09 by Simon.Tourangeau Fix actor mobility getting changed on scene reimport #jira UE-39102 Change 3229692 on 2016/12/09 by Cody.Albert Fixing an XML Parser assert when parsing a root tag that completes on the same line. #jira UE-30393 Change 3230582 on 2016/12/12 by Matt.Kuhlenschmidt PR #3024: Correct the outdated error message instructions for how to fix being unable to launch on an iOS device. (Contributed by CleanCut) Change 3231470 on 2016/12/12 by Matt.Kuhlenschmidt Eliminate editor sounds that play when you PIE, simulate or possess the player. They get in the way of game sounds, are annoying to hear when you are constantly starting and stopping pie, and flush async loading that the game might be doing when they load. Change 3231475 on 2016/12/12 by Alex.Delesky #jira UE-39023 - Using the High Resolution screenshot tool with the "custom depth as mask" option checked should no longer crash the editor or a PIE viewport when the screen percentage is not set to 100. Change 3231476 on 2016/12/12 by Alex.Delesky #jira UE-39380 - Thumbnails for static meshes in the foliage paint mode window should now update to show the correct mesh if the thumbnail pool has been exhausted. This also increases the number of foliage thumbnals that can exist onscreen at once. Change 3231477 on 2016/12/12 by Alex.Delesky #jira none - Extending the IPluginWizardDefinition interface to allow it to return the descriptor type of the plugin. This fixes a merge conflict from Odin where the new plugin wizard was modified to allow for multiple template selection. Change 3231479 on 2016/12/12 by Alex.Delesky #jira UE-39376 - Changing the number of players or changing the dedicated server options in PIE settings should now always persist on editor shutdown. Change 3231480 on 2016/12/12 by Alex.Delesky #jira UE-39417 - A texture will now match to update a dropped in file if the source path differs from that of the dropped in file Change 3231508 on 2016/12/12 by Alex.Delesky Removing todo comment #jira none Change 3231603 on 2016/12/12 by Matt.Kuhlenschmidt Exposed a 0-1 UV set and the scaled pixel size for Box and Border brushes Also added a material function that exposes all of the current UV sets with nice names instead of indexed coordinates Change 3231618 on 2016/12/12 by Alex.Delesky #jira UE-38732 - When editing a spin box with a delta value, committing the value with the Enter key and then clearing the focus from the spin box will no longer change the internal value to match the snapped value. Change 3231638 on 2016/12/12 by Matt.Kuhlenschmidt Add RF_Transactional to the list of default flags for creating or importing new assets. All should be transactional by default Change 3231642 on 2016/12/12 by Matt.Kuhlenschmidt Brighten up the output log by default Change 3231648 on 2016/12/12 by Alex.Delesky #jira UE-38033 - Selecting a Named Slot that's part of a widget in a Widget Switcher will now show that widget instead of the widget at index 0. This also applies to any content set inside the named slot. Change 3231666 on 2016/12/12 by Alex.Delesky #jira UE-38952 - Widgets that have been copied and pasted into the same hierarchy will now retain the same name in the hierarchy. This does not fix widgets that have been previously copied and pasted from other widgets, nor copies of those widgets. Change3231674on 2016/12/12 by Alex.Delesky #jira UE-37106 - When using or simulating touch for Widget Components, the hover/clicked state will now be accurately determined rather than showing hover on initial touch. Change 3231745 on 2016/12/12 by Alex.Delesky Back out changelist 3231477 to fix build error C2259 Change3232417on 2016/12/13 by Simon.Tourangeau Add the following attributes to the Editor.Usage.FBX.Import EngineAnalytics event - FBX Version - Filename Hash - Import Type #jira UE-37453 Change 3232477 on 2016/12/13 by Michael.Dupuis #jira UE-39675 : There was an issue when the Neutral Value == the Min or Max value, so we simply prevent using the concept of neutral value if min or max == neutral as it mean you only want a log on one side. Change 3232571 on 2016/12/13 by Alex.Delesky Back out changelist 3231745 #jira none - Extending the IPluginWizardDefinition interface to allow it to return the descriptor type of the plugin. This fixes a merge conflict from Odin where the new plugin wizard was modified to allow for multiple template selection. Change3232675on 2016/12/13 by Alexis.Matte Fix a crash when reordering material with a fbx containing unused materials, add a fbx automation test to prevent similar issue. #jira UE-39692 Change 3232975 on 2016/12/13 by Alex.Delesky Fix to build error C2259 for the IPluginWizardDefinition API change. Change 3233146 on 2016/12/13 by Michael.Dupuis #jira UE-38766 : Added eye dropper to select flatten height Fixed a rounding errors resulting in not flattening to the specified height Fixed a rounding error resulting in LandscapeDataAccess::GetTexHeight not always returning the appropriate value Change 3233153 on 2016/12/13 by Alexis.Matte We cannot anymore change the instance override materials array topology, the topology is limited by the mesh materials array #jira UE-38827 Change 3234406 on 2016/12/14 by Matt.Kuhlenschmidt Fix window handle and device context being accessed by scene viewports after the underlying window has been destroyed by the OS. This is an invalid state on linux and using some vr devices. #jira UE-7388 Change 3234485 on 2016/12/14 by Michael.Dupuis tentative build fix for Mac Change 3234495 on 2016/12/14 by Matt.Kuhlenschmidt Made a setting to control if PIE enter and exit sounds are played. Off by default Change 3236709 on 2016/12/15 by Simon.Tourangeau Fix camera export rotation offset #jira UE-34692 #jira UE-39740 Change 3236782 on 2016/12/15 by Jamie.Dale Fixed EmitTermExpr failing to use the correct package ID FBPTerminal::Source used to be set to the pin, however when pins were moved away from being UObjects, FBPTerminal::SourcePin was added and FBPTerminal::Source is typically null. Change 3236853 on 2016/12/15 by Alexis.Matte Fix the serialization of the staticmesh property FMeshSectionInfoMap Change 3236890 on 2016/12/15 by Matt.Kuhlenschmidt Remove old define Change 3239328 on 2016/12/18 by Richard.TalbotWatkin Fixed Focus Viewport action in Static Mesh Viewport. Problem was that the conversion to Orbit Camera for storing the camera position was trashing the desired position during cvamera transitions. Orbit camera position is now only stored at the end of a transition. #jira UE-39825 - Key "F" for Focus acts Sporadically in the Static Mesh Editor Viewport Change 3239660 on 2016/12/19 by Alex.Delesky #jira UE-38968, UE-36826 - Components attached to actors can now be directly scaled to negative values using the transform gizmo for that component. Change 3239662 on 2016/12/19 by Alex.Delesky #jira UE-39007 - The data table row editor now contains a Reset to Default control. Change 3239663 on 2016/12/19 by Alex.Delesky #jira UE-39698 - Importing CSV files will now show the name of the file in the import dialog. Change 3240696 on 2016/12/20 by Michael.Dupuis #jira UETOOL-1009: Added paddiing to columns view Added auto resize of column when double clicking on splitter handle in the header Remove right number alignment after discussion with Matt K. Change 3240758 on 2016/12/20 by Michael.Dupuis added missing non abstract implementation Change 3240782 on 2016/12/20 by Michael.Dupuis Added missing documentation for content browser column auto resizing Change 3240817 on 2016/12/20 by Alex.Delesky #jira UE-38940 - Copying a Material-Custom node with a tab character should now correctly render the tab. Change 3240834 on 2016/12/20 by Michael.Dupuis tentative fix for build error Change 3240984 on 2016/12/20 by Michael.Dupuis Removed unnecessary functions Change 3241174 on 2016/12/20 by Matt.Kuhlenschmidt Fix compile errors Change 3241966 on 2016/12/21 by Chris.Wood Fixed Typo and changed execution order in "ComboBoxString" Component [UE-38994] - GitHub 2971 : Fixed Typo and changed execution order in "ComboBoxString" Component PR #2971: Fixed Typo and changed execution order in "ComboBoxString" Component (Contributed by eXifreXi) #github https://github.com/EpicGames/UnrealEngine/pull/2971 Change 3242126 on 2016/12/21 by Alexis.Matte Back out changelist 3236853 We have to back out this change list because the change was implement in the 4.15 release branch and the EditorObjectVersion.h change is now implement in the ReleaseObjectVersion.h. Change 3244492 on 2017/01/02 by Jamie.Dale Improved error message Change 3244545 on 2017/01/02 by Nick.Darnell Navigation - Making it so we don't attempt to load HotReload during shutdown, we only access it if it's still loaded. Change 3244549 on 2017/01/02 by Nick.Darnell Slate - Implementing custom hardware cursor loading across Windows, Mac and Linux and supports loading cursors from PAK files. All platforms support loading PNGs through the FHardwareCursor interface. Some platforms support additional formats, for multiresolution support, but there's a naming convention that can be used on PNGs for the same capability. All of it is documented in the FHardwareCursor header. The platform layer for ICursor, now has support for replacing cursor shapes as an override, and can be reset safely. The FHardwareCursor supports loading cursors from raw pixel buffers as well, the plan is to allow for the option to UTextures to also be used for hardware cursors. Now users through C++ can load and replace the hardware cursors with custom ones of their own, e.g. FSlateApplication::Get().RegisterCursor(EMouseCursor::Default, MakeShareable(new FHardwareCursor(FPaths::GameContentDir() / "Slate/FancyPointer", FIntPoint(0,0)))); The next step is to expose a game friendly layer that supports caching cursors, and letting users change them out by name, without a bunch of destruction of OS resources. Change 3244845 on 2017/01/03 by Jamie.Dale Fixing typo #jira UE-39920 Change 3244903 on 2017/01/03 by Jamie.Dale PR #3044: fix link error when FAssetData::PrintAssetData() is used in project (Contributed by kayama-shift) Change 3245125 on 2017/01/03 by Alexis.Matte Put back the dev-editor version because there was some data create before we back it out Change 3246106 on 2017/01/04 by Chris.Wood Removed broken CrashReportReciever pre-upload phase from CrashReportClient. [UE-40153] - CrashReportClient fails when used in legacy mode with a CrashReportReciever Change 3246251 on 2017/01/04 by Alex.Delesky #jira UE-39869 - Moving an asset before saving it and then hitting Save All from the file menu will no longer save the asset in its original location. Change 3246252 on 2017/01/04 by Alex.Delesky #jira UE-39793 - Fixes an issue with the AutoReimporter where specifying a non-existent mount point (a directory in the content browser) would cause a crash when attempting to auto-import an asset from a monitored directory, as well as ensuring that valid mount points will be able to create new assets from auto-import. The "Map Directory To" field when setting directories to monitor for auto-reimport has also been changed to use the content browser path picker instead of relying on the user to manually enter a mount point. Change 3247620 on 2017/01/05 by Nick.Darnell Automation - Removing an adjustment to the number of shots we take for high res shots. Change 3247621 on 2017/01/05 by Nick.Darnell Automation - Adding a few more rendering tests to the cornell box. Change 3247629 on 2017/01/05 by Nick.Darnell Automation - Improving the comparison row display for screenshots so it's obvious what each image represents. Change 3248811 on 2017/01/05 by Matt.Kuhlenschmidt PR #3091: Removed unnecessary UPackage casts (Contributed by projectgheist) Change 3248860 on 2017/01/06 by Matt.Kuhlenschmidt Made the plugin browser select the "built in" category by default instead of the 2D category. There is no reason for a sub-category to be selected first as it makes searching for plugins globally an extra click because you have to click on the base category first Change 3249264 on 2017/01/06 by Matt.Kuhlenschmidt Fixed automation test warnings #jira UE-40198 Change 3249481 on 2017/01/06 by Michael.Dupuis #jira UE-37875 : Fill empty layers of components on assignation or creation Also fill new component added with the tool from neighbours predominance Change 3249505 on 2017/01/06 by Matt.Kuhlenschmidt PR #3093: Include guard cleanup (Contributed by projectgheist) Change 3249544 on 2017/01/06 by Michael.Dupuis #jira UE-40299: validate if UISettings is valid Change 3250738 on 2017/01/09 by Nick.Darnell UMG - The WIC now checks if the Widget is enabled before it claims that it's over an interactable or keyboard focusable widget. #jira UE-39845 Change 3250865 on 2017/01/09 by Nick.Darnell Slate - Updating EAutoCenter and ESizingRule to use the newer enum class style enums. Change 3250867 on 2017/01/09 by Nick.Darnell Slate - Adding more logging to the hardware cursor code so that it reports more information when it doesn't find an exact match when it comes to cursor size. Change 3250936 on 2017/01/09 by Nick.Darnell Automation - Refactoring the screenshot comparison tool to no longer require one one generated report. Doing screenshot comparions now generates individual reports for each failed comparison so that they can be evaluated in bits, and as changes occur as the user reviews aspects, we can remove the reports. There is now async image loading for the comparison view so that it doesn't hitch. Change 3250937 on 2017/01/09 by Nick.Darnell Automation - Adding another example to the CornellBox test. Change 3250958 on 2017/01/09 by Nick.Darnell Slate - Fixing some other cases where people were referring to ESizingRule::Type. Change 3251162 on 2017/01/09 by Nick.Darnell Slate - Fixing some other cases where people were referring to ESizingRule::Type. Change 3251254 on 2017/01/09 by Matt.Kuhlenschmidt Attempt to fix static analysis warnings Change 3251373 on 2017/01/09 by Nick.Darnell Core - Now writing a log warning instead of ensuring if calling LoadModule wouldn't have been safe to do here, depending on load order. Change 3251525 on 2017/01/09 by Nick.Darnell Automation - Fixing a build issue in ImageComparer. Change 3252321 on 2017/01/10 by Alex.Delesky #jira UE-40164 - Importing multiple files to overwrite existing assets such as sounds will now correctly persist the "Yes to All" / "No to All" dialog selections. Change 3252354 on 2017/01/10 by Nick.Darnell Image Compare - Fixing a potential threading hazard in the image comparer. Change 3252356 on 2017/01/10 by Nick.Darnell Automation - The screenshot metadata now captures the commit/CL that the screenshot was taken at and records it in the metadata. Change 3252601 on 2017/01/10 by Alexis.Matte Fbx automation test, reload feature implementation Change 3252761 on 2017/01/10 by Jamie.Dale Fixing some IWYU errors with PCH disabled Change 3252765 on 2017/01/10 by Jamie.Dale Fixing some static analysis warnings Change 3252793 on 2017/01/10 by Jamie.Dale Fixing FText natvis The text data visualizers have to be defined before the text visualizer Change 3253987 on 2017/01/11 by Matt.Kuhlenschmidt PR #3108: Git Plugin: use asynchronous "MarkForAdd" and "CheckIn" operations for the initial commit (Contributed by SRombauts) Change 3254378 on 2017/01/11 by Matt.Kuhlenschmidt Refactor scene importing to allow for plugins to make scene importers Change 3254679 on 2017/01/11 by Matt.Kuhlenschmidt Fix calling LoadModule in perforce source control off the main thread Change 3256472 on 2017/01/12 by Jamie.Dale Improved error reporting from IncludeTool - The error reporting was using zero-based line indices which was misleading. - The error reporting now includes the offending line to remove ambiguity. Change 3256725 on 2017/01/13 by Jamie.Dale IncludeTool can now parse typedef in Fwd headers Change 3256758 on 2017/01/13 by Jamie.Dale Added support for String Tables String Tables provide a way to centralize your localized text into one (or several) known locations, and then reference the entries within a string table from other assets or code in a robust way that allows for easy re-use of localized text. String Tables can be defined in C++ (using the LOCTABLE family of macros), loaded via CSV file, or created as an asset. They can be referenced in C++ using either the LOCTABLE macro, or the static FText::FromStringTable function. INI files can reference them using the LOCTABLE macro syntax, and FText properties in assets can reference them via the advanced settings combo. Change 3257018 on 2017/01/13 by Alexis.Matte FbxAutomationTest fix the import reload operation, it was calling garbagecollect with no keep flag Change 3257168 on 2017/01/13 by Jamie.Dale Removed code that was writing null into bytecode during save Change 3257344 on 2017/01/13 by Jamie.Dale Backing out changelist 3256725, and excluding my header from the scan instead Change 3257426 on 2017/01/13 by Nick.Darnell Slate - Adding the ability to invert alpha when drawing slate textures. Going to be used in the future for rendering render targets for the scene which have inverted alpha. Change 3257572 on 2017/01/13 by Nick.Darnell Slate - Fixing a build error. Change 3257970 on 2017/01/14 by Jamie.Dale Fixing exclude path Change 3258458 on 2017/01/16 by Matt.Kuhlenschmidt PR #3135: GameViewportClient: FOnCloseRequested is now a multicast delegate (Contributed by Nadrin) Change 3258472 on 2017/01/16 by Matt.Kuhlenschmidt PR #3126: Fix to load editor style assets (Contributed by projectgheist) Change 3258473 on 2017/01/16 by Matt.Kuhlenschmidt PR #3124: Fix wrong result with Image-DrawAsBox with PaperSprite. (Contributed by valval88) Change 3258539 on 2017/01/16 by Nick.Darnell Slate - Pixel Snapping has been moved to the GPU for the RHI rendering policy. Additionally, widgets with a render transform of Scale, Rotation or Sheer, and their children are no longer pixel snapped, this should reduce some of jittering seen by users when animations are applied to widgets. NOTE: This only affects render transforms, any transform in layout space is still subject to pixel snapping. Change 3258607 on 2017/01/16 by Nick.Darnell Fixing the mac build. Change 3258661 on 2017/01/16 by Matt.Kuhlenschmidt Actors with experimental components no longer say "Uses experimental class: Actor" when selecting the actor root in the details panel #jira UE-40535 Change 3258678 on 2017/01/16 by Nick.Darnell Platform - Introducing a way to get the mimetype for a file on Windows. Other platforms don't yet have an implementation outside of returning application/unknown. Change 3258924 on 2017/01/16 by Nick.Darnell Platform - Implementing a fallback for the generic platform http, that can do some basic mimetype lookups. Change 3258929 on 2017/01/16 by Nick.Darnell UMG - Fixing the animation to finish the evaluation before it notifies that the animation completed. Change 3259109 on 2017/01/16 by Nick.Darnell Platform - The GetMimeType function now only takes in FilePath, since some platforms will require that actually resolve to a file on disk in order to determine the true mimetype. Change 3259111 on 2017/01/16 by Alexis.Matte Avoid to move the camera when we re-import in the static mesh editor #jira UE-40613 Change 3259275 on 2017/01/16 by Matt.Kuhlenschmidt Fix crash when a slate window is resized and calls into a scene viewport during loading code when the scene viewport is not in a slate hierarchy and thus has no widget Change 3259300 on 2017/01/16 by Nick.Darnell UMG - Introducing PreConstruct and NativePreConstruct to the base UUserWidget. Users can now visualize non-binding based changes in the designer by evaluating a very limited amount of the blueprint code. In the event your user widget crashes on load, due to calling something unsafe, you can disable evaluation in the editor preferences under Widget Designer. Change 3259306 on 2017/01/16 by Nick.Darnell Games - Removing the Game Specific implementations of PreConstruct. Change 3260182 on 2017/01/17 by Matt.Kuhlenschmidt Fix static analysis Change 3261049 on 2017/01/17 by Nick.Darnell Slate - Putting in some fixes for the non-gpu pixel snapping mode, and disabling gpu snapping while we dig into why it looks weird. Change 3261434 on 2017/01/17 by Nick.Darnell Fixing the mac build. Change 3261435 on 2017/01/17 by Nick.Darnell Slate - Tweaking some aspects of the slate rounding code on the GPU. There's still some precision loss somewhere causing subtle differences in where the snap occurs, that's different from previously. Change 3261460 on 2017/01/17 by Nick.Darnell UMG - Tweaking the defintiions of NativePreConstruct, dropping passing in design time since that is readily available in native code. Change 3261833 on 2017/01/18 by Alexis.Matte Fix all warning for fbx automation tests #jira UE-40208 Change 3261874 on 2017/01/18 by Matt.Kuhlenschmidt PR #3136: Fix Submit to Source Control Window for Git plugin : use CanCheckIn() to filter out unmodified assets files (Contributed by SRombauts) Change 3262000 on 2017/01/18 by Jamie.Dale Updated Slate to allocate widgets using MakeShared This saves one allocation per-widget Change 3262003 on 2017/01/18 by Nick.Darnell UMG - Widget Interaction Components now ignore Visible(false) Widget Components when tracing. #jira UE-40523 Change 3262052 on 2017/01/18 by Alexis.Matte Put back the staticmesh skinxx workflow #jira UE-40782 Change 3262775 on 2017/01/18 by Nick.Darnell Slate - Ditching moving vertex rounding to the GPU, some precision issues could not be overcome. Ended up writing a clean way to implement it on the CPU. Change 3262818 on 2017/01/18 by Alex.Delesky #jira UE-40668 - Editor preferences will now save for data pin styles Change 3263679 on 2017/01/19 by Nick.Darnell Slate - Adding some comments to the Slate Vertex Rounder. Change 3265154 on 2017/01/19 by Nick.Darnell Slate/UMG - Putting in some more time into pixel snapping. I've re-introduced the old constructors, and decided to go with the templated approach, as to not break old code that relied on the FSlateVertex working a certain way. Change 3265478 on 2017/01/20 by Chris.Wood Added config support for hang detection time and switching hang detection on/off in UnrealWatchdog [UE-40838] - Make hang time configurable and increase default in UnrealWatchdog Change3265600on 2017/01/20 by Nick.Darnell Slate - Making some const local variables const. Change 3265714 on 2017/01/20 by Alex.Delesky #jira UE-40791 - The ForceFeedback thumbnail's Play and Stop icons will now render correctly, and will only be visible while an effect is playing or when the cursor hovers over the icon. Change 3265865 on 2017/01/20 by Alex.Delesky #jira UE-40511 - The Content Browser file path will now update when inside a folder that is deleted from the Sources Panel. Change 3267989 on 2017/01/23 by Jamie.Dale Exposed String Tables to Blueprints Change 3268018 on 2017/01/23 by Jamie.Dale Small API clean-up for string tables Change 3268455 on 2017/01/23 by Matt.Kuhlenschmidt Fix SaveAs (Which says SaveCurrentAs) not saving the current level and only saving the persistent level and then reloading everything thus causing work to be lost if editing a sub-level #jira UE-40930 Change 3269388 on 2017/01/24 by Chris.Wood Refactored tick timing in UnrealWatchdog to stop bug where it doesn't close. [UE-40839] - UnrealWatchdog running and blocking use of Unreal Game Sync for internal users Standalone tool code only - doesn't touch engine Change 3270205 on 2017/01/24 by Cody.Albert Updated FUnrealEdMisc::OnMessageTokenActivated to properly traverse up the outer hierarchy of an object. Change 3270231 on 2017/01/24 by Cody.Albert Renamed and exposed GetFullScreenAlignment and GetViewportAnchors for consistency with the setters Change 3271734 on 2017/01/25 by Michael.Dupuis #jira UE-38631 Add sorting for landscape target layer, user can now sort alphabetical, material based or custom Added a new vertical box SDragNDropVerticalBox to handle drag & drop of FSlot Fixed SDropTarget to only consider the drop action if it was started by it Added visibility toggle to only show used layers in the currently loaded data Change 3271797 on 2017/01/25 by Jamie.Dale Renamed HasBeenAlreadyMadeSharable to DoesSharedInstanceExist as the old name was nonsense Change 3271813 on 2017/01/25 by Jamie.Dale Fixed bad access of a shared this during widget destruction when a context menu was open Change 3271988 on 2017/01/25 by Nick.Darnell Slate - Removing some old checkbox deprecated code from the 4.3 and 4.6 days. Change 3271992 on 2017/01/25 by Nick.Darnell Blueprints - Making the checked call better to log out more information when dragging and dropping a missing property. Change 3272134 on 2017/01/25 by Jamie.Dale Updated the GatherText commandlet to no longer hold a ConfigFile pointer while it runs This pointer is internal to GConfig, and may be updated (or invalidated) when other config files are loaded (as can happen via game code while gathering text). Change 3272301 on 2017/01/25 by Nick.Darnell Slate - More cleanup from the removal of a old legacy enum that people were still using. Change 3273070 on 2017/01/26 by Chris.Wood Fix CIS errors in landscape code from CL 3271734 Change 3273123 on 2017/01/26 by Chris.Wood Fix crash during init of CRC when running packaged without access to main engine config hierarchy. Change 3273194 on 2017/01/26 by Nick.Darnell Fixing some build warnings. Change 3273242 on 2017/01/26 by Michael.Dupuis #jira UE-39948 : if we detect there is multiple levels in the current persistent when we add a new foliage asset we ask to save the foliage as an asset to permit paiting over multiple levels Change 3273279 on 2017/01/26 by Jamie.Dale String Table INI redirects are now in the "Core.StringTable" section (rather than "/Script/Engine.Engine") Change 3273483 on 2017/01/26 by Alex.Delesky #jira UE-32047 - Made changes to the FixupRedirects commandlet to ensure that files that are marked for delete are moved from the default changelist to the pending changelist and submitted when using Perforce. Also makes a slight change to the ResavePackages commandlet to submit files marked for delete. Change 3273568 on 2017/01/26 by Alex.Delesky Modifying changes made to SPluginWizard to have the plugin loading phase determined by the wizard's definition rather than from the first selected template. #jira none Change 3273855 on 2017/01/26 by Alex.Delesky #jira UE-41117 - Updating the tooltip on the "Allow Paint of all LODs" option for mesh paint mode. Change 3274200 on 2017/01/26 by Alex.Delesky For IPluginWizardDefinition, temporarily adding function bodies to two methods instead of having them be pure virtual methods. Change 3274317 on 2017/01/26 by Jamie.Dale Deleting a seemingly corrupted asset that was accidentially submitted Change 3275072 on 2017/01/27 by Michael.Dupuis #jira UE-38631 tweaks Fix typo error Iterate all components, not only active one Force expand the Target Layers widget Change 3275249 on 2017/01/27 by Alexis.Matte Color grading controls: Keep the vector ratio when changing the master slider #jira UETOOL-1098 Change 3275282 on 2017/01/27 by Alexis.Matte Color grading controls: Cosmetic changes #jira UETOOL-1099 Change 3275292 on 2017/01/27 by Alexis.Matte Make sure the build is called once when we import a staticmesh. #jira UE-40947 Change 3275430 on 2017/01/27 by Alexis.Matte Add some fbx automation tests - Import a mesh with no material - Import corrupted asset with no section in a LOD - Import morph targets - Materials name clash - Max Multimap material ordering Change 3275683 on 2017/01/27 by Michael.Dupuis #jira UE-41215 : when saving an asset do not register the transaction, and make sure that the duplicate wont keep a copy in the transaction buffer as an asset can't be undo Change 3276237 on 2017/01/27 by Jamie.Dale Deleting a seemingly corrupted asset that was accidentially submitted Change 3276266 on 2017/01/27 by Jamie.Dale Fix for accessing a potentially null pointer Change 3277065 on 2017/01/30 by Chris.Wood Move crash report temp files to saved config and cleanup on schedule. [UE-39506] - CrashReportClient ini folders are not cleaned when opening the editor Change 3277236 on 2017/01/30 by Matt.Kuhlenschmidt Fix crash when cancelling SaveCurrentLevelAs #jira UE-41182 Change 3277409 on 2017/01/30 by Jamie.Dale Improved text rendering when the last resort font is missing The last resort font is no longer included in shipping builds, so this change makes some improvements to text rendering when it's missing. - The legacy font cache no longer tries to use the last resort font if it's not available (preventing warnings). - The Slate font renderer no longer tries to use the last resort font if it's not available. - Text shaping will use the last resort character if none of the available fonts can render a given character (likely because the last resort font is missing). - HarfBuzz shaped text now uses the fallback character correctly. Change 3277749 on 2017/01/30 by Nick.Darnell Slate - Moving ESlateDrawEffect & ESlateBatchDrawFlag over to be enum class, found cases where users were improperly assuming the enum order, and so now it won't be possible to just treat an int32 or a bool as the draw effect value. Core - Adding EnumHasAllFlags and EnumHasAnyFlags, templated functions to make it easier to check for the existance of a flag on enum classes. Change 3277805 on 2017/01/30 by Nick.Darnell Rendering - Changing some LoadModuleChecked calls to GetModuleChecked, as these calls are not happening on the main thread and are not safe to make. Change 3277914 on 2017/01/30 by Matt.Kuhlenschmidt Fix Niagara slate style warning on startup Change 3278058 on 2017/01/30 by Matt.Kuhlenschmidt Fixed compile error Change 3278132 on 2017/01/30 by Nick.Darnell Fixed compile error Change 3278133 on 2017/01/30 by Matt.Kuhlenschmidt Fixed compile errors Change 3278186 on 2017/01/30 by Nick.Darnell Fixed compile error Change 3278525 on 2017/01/30 by Nick.Darnell Fixed compile error Change 3278534 on 2017/01/30 by Nick.Darnell Automation - Clearing up several warnings/errors with automation results, trying to get Automation Tests to at least yellow before integration. Change 3278941 on 2017/01/31 by Nick.Darnell Fixing a build warning due to build team refactor. Change 3278949 on 2017/01/31 by Nick.Darnell Fixing incrmenetal build issues. Change 3278953 on 2017/01/31 by Nick.Darnell Fixing some incrmental linux build issues. Change 3278964 on 2017/01/31 by Nick.Darnell FIxing more incremental build issues. Change 3279256 on 2017/01/31 by Michael.Dupuis #jira UE-41319 #jira UE-41315 #jira UE-41316 Instead of getting the Landscape Actor, call GetLandscapeProxy so all case are handled, either proxy or landscape actor Change 3279270 on 2017/01/31 by Chad.Garyet re-updating the automation test pool [CL 3279775 by Matt Kuhlenschmidt in Main branch]
2083 lines
72 KiB
C++
2083 lines
72 KiB
C++
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Misc/MessageDialog.h"
|
|
#include "Misc/ScopedSlowTask.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Engine/EngineTypes.h"
|
|
#include "LandscapeToolInterface.h"
|
|
#include "LandscapeProxy.h"
|
|
#include "LandscapeGizmoActiveActor.h"
|
|
#include "LandscapeEdMode.h"
|
|
#include "LandscapeEditorObject.h"
|
|
#include "Landscape.h"
|
|
#include "LandscapeStreamingProxy.h"
|
|
#include "ObjectTools.h"
|
|
#include "LandscapeEdit.h"
|
|
#include "LandscapeComponent.h"
|
|
#include "LandscapeRender.h"
|
|
#include "PropertyEditorModule.h"
|
|
#include "InstancedFoliageActor.h"
|
|
#include "LandscapeEdModeTools.h"
|
|
#include "PhysicalMaterials/PhysicalMaterial.h"
|
|
#include "Materials/MaterialExpressionLandscapeVisibilityMask.h"
|
|
#include "Containers/Algo/Copy.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "Landscape"
|
|
|
|
//
|
|
// FLandscapeToolSelect
|
|
//
|
|
class FLandscapeToolStrokeSelect : public FLandscapeToolStrokeBase
|
|
{
|
|
bool bInitializedComponentInvert;
|
|
bool bInvert;
|
|
bool bNeedsSelectionUpdate;
|
|
|
|
public:
|
|
FLandscapeToolStrokeSelect(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
, bInitializedComponentInvert(false)
|
|
, bNeedsSelectionUpdate(false)
|
|
, Cache(InTarget)
|
|
{
|
|
}
|
|
|
|
~FLandscapeToolStrokeSelect()
|
|
{
|
|
if (bNeedsSelectionUpdate)
|
|
{
|
|
TArray<UObject*> Objects;
|
|
if (LandscapeInfo)
|
|
{
|
|
TSet<ULandscapeComponent*> SelectedComponents = LandscapeInfo->GetSelectedComponents();
|
|
Objects.Reset(SelectedComponents.Num());
|
|
Algo::Copy(SelectedComponents, Objects);
|
|
}
|
|
FPropertyEditorModule& PropertyModule = FModuleManager::Get().LoadModuleChecked<FPropertyEditorModule>(TEXT("PropertyEditor"));
|
|
PropertyModule.UpdatePropertyViews(Objects);
|
|
}
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
if (LandscapeInfo)
|
|
{
|
|
LandscapeInfo->Modify();
|
|
|
|
// TODO - only retrieve bounds as we don't need the data
|
|
const FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Shrink bounds by 1,1 to avoid GetComponentsInRegion picking up extra components on all sides due to the overlap between components
|
|
TSet<ULandscapeComponent*> NewComponents;
|
|
LandscapeInfo->GetComponentsInRegion(X1 + 1, Y1 + 1, X2 - 1, Y2 - 1, NewComponents);
|
|
|
|
if (!bInitializedComponentInvert)
|
|
{
|
|
// Get the component under the mouse location. Copied from FLandscapeBrushComponent::ApplyBrush()
|
|
const float MouseX = InteractorPositions[0].Position.X;
|
|
const float MouseY = InteractorPositions[0].Position.Y;
|
|
const int32 MouseComponentIndexX = (MouseX >= 0.0f) ? FMath::FloorToInt(MouseX / LandscapeInfo->ComponentSizeQuads) : FMath::CeilToInt(MouseX / LandscapeInfo->ComponentSizeQuads);
|
|
const int32 MouseComponentIndexY = (MouseY >= 0.0f) ? FMath::FloorToInt(MouseY / LandscapeInfo->ComponentSizeQuads) : FMath::CeilToInt(MouseY / LandscapeInfo->ComponentSizeQuads);
|
|
ULandscapeComponent* MouseComponent = LandscapeInfo->XYtoComponentMap.FindRef(FIntPoint(MouseComponentIndexX, MouseComponentIndexY));
|
|
|
|
if (MouseComponent != nullptr)
|
|
{
|
|
bInvert = LandscapeInfo->GetSelectedComponents().Contains(MouseComponent);
|
|
}
|
|
else
|
|
{
|
|
bInvert = false;
|
|
}
|
|
|
|
bInitializedComponentInvert = true;
|
|
}
|
|
|
|
TSet<ULandscapeComponent*> NewSelection;
|
|
if (bInvert)
|
|
{
|
|
NewSelection = LandscapeInfo->GetSelectedComponents().Difference(NewComponents);
|
|
}
|
|
else
|
|
{
|
|
NewSelection = LandscapeInfo->GetSelectedComponents().Union(NewComponents);
|
|
}
|
|
|
|
LandscapeInfo->Modify();
|
|
LandscapeInfo->UpdateSelectedComponents(NewSelection);
|
|
|
|
// Update Details tab with selection
|
|
bNeedsSelectionUpdate = true;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
FLandscapeDataCache Cache;
|
|
};
|
|
|
|
class FLandscapeToolSelect : public FLandscapeToolBase<FLandscapeToolStrokeSelect>
|
|
{
|
|
public:
|
|
FLandscapeToolSelect(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokeSelect>(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("Select"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_Selection", "Component Selection"); };
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::SelectComponent | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return false; }
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolMask
|
|
//
|
|
class FLandscapeToolStrokeMask : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeMask(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
, Cache(InTarget)
|
|
{
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
if (LandscapeInfo)
|
|
{
|
|
LandscapeInfo->Modify();
|
|
|
|
// Invert when holding Shift
|
|
bool bInvert = InteractorPositions[ InteractorPositions.Num() - 1].bModifierPressed;
|
|
|
|
const FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Tablet pressure
|
|
float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.0f;
|
|
|
|
Cache.CacheData(X1, Y1, X2, Y2);
|
|
TArray<uint8> Data;
|
|
Cache.GetCachedData(X1, Y1, X2, Y2, Data);
|
|
|
|
TSet<ULandscapeComponent*> NewComponents;
|
|
LandscapeInfo->GetComponentsInRegion(X1, Y1, X2, Y2, NewComponents);
|
|
LandscapeInfo->UpdateSelectedComponents(NewComponents, false);
|
|
|
|
for (int32 Y = BrushInfo.GetBounds().Min.Y; Y < BrushInfo.GetBounds().Max.Y; Y++)
|
|
{
|
|
const float* BrushScanline = BrushInfo.GetDataPtr(FIntPoint(0, Y));
|
|
uint8* DataScanline = Data.GetData() + (Y - Y1) * (X2 - X1 + 1) + (0 - X1);
|
|
|
|
for (int32 X = BrushInfo.GetBounds().Min.X; X < BrushInfo.GetBounds().Max.X; X++)
|
|
{
|
|
const FIntPoint Key = FIntPoint(X, Y);
|
|
const float BrushValue = BrushScanline[X];
|
|
|
|
if (BrushValue > 0.0f && LandscapeInfo->IsValidPosition(X, Y))
|
|
{
|
|
float PaintValue = BrushValue * UISettings->ToolStrength * Pressure;
|
|
float Value = DataScanline[X] / 255.0f;
|
|
checkSlow(FMath::IsNearlyEqual(Value, LandscapeInfo->SelectedRegion.FindRef(Key), 1 / 255.0f));
|
|
if (bInvert)
|
|
{
|
|
Value = FMath::Max(Value - PaintValue, 0.0f);
|
|
}
|
|
else
|
|
{
|
|
Value = FMath::Min(Value + PaintValue, 1.0f);
|
|
}
|
|
if (Value > 0.0f)
|
|
{
|
|
LandscapeInfo->SelectedRegion.Add(Key, Value);
|
|
}
|
|
else
|
|
{
|
|
LandscapeInfo->SelectedRegion.Remove(Key);
|
|
}
|
|
|
|
DataScanline[X] = FMath::Clamp<int32>(FMath::RoundToInt(Value * 255), 0, 255);
|
|
}
|
|
}
|
|
}
|
|
|
|
Cache.SetCachedData(X1, Y1, X2, Y2, Data);
|
|
Cache.Flush();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
FLandscapeDataCache Cache;
|
|
};
|
|
|
|
class FLandscapeToolMask : public FLandscapeToolBase<FLandscapeToolStrokeMask>
|
|
{
|
|
public:
|
|
FLandscapeToolMask(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokeMask>(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("Mask"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_Mask", "Region Selection"); };
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::SelectRegion | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return true; }
|
|
|
|
virtual ELandscapeToolType GetToolType() override { return ELandscapeToolType::Mask; }
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolVisibility
|
|
//
|
|
class FLandscapeToolStrokeVisibility : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeVisibility(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
, Cache(InTarget)
|
|
{
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
if (LandscapeInfo)
|
|
{
|
|
LandscapeInfo->Modify();
|
|
// Get list of verts to update
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Invert when holding Shift
|
|
bool bInvert = InteractorPositions[InteractorPositions.Num() - 1].bModifierPressed;
|
|
|
|
// Tablet pressure
|
|
float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.0f;
|
|
|
|
Cache.CacheData(X1, Y1, X2, Y2);
|
|
TArray<uint8> Data;
|
|
Cache.GetCachedData(X1, Y1, X2, Y2, Data);
|
|
|
|
for (int32 Y = BrushInfo.GetBounds().Min.Y; Y < BrushInfo.GetBounds().Max.Y; Y++)
|
|
{
|
|
const float* BrushScanline = BrushInfo.GetDataPtr(FIntPoint(0, Y));
|
|
uint8* DataScanline = Data.GetData() + (Y - Y1) * (X2 - X1 + 1) + (0 - X1);
|
|
|
|
for (int32 X = BrushInfo.GetBounds().Min.X; X < BrushInfo.GetBounds().Max.X; X++)
|
|
{
|
|
const float BrushValue = BrushScanline[X];
|
|
|
|
if (BrushValue > 0.0f)
|
|
{
|
|
uint8 Value = bInvert ? 0 : 255; // Just on and off for visibility, for masking...
|
|
DataScanline[X] = Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
Cache.SetCachedData(X1, Y1, X2, Y2, Data);
|
|
Cache.Flush();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
FLandscapeVisCache Cache;
|
|
};
|
|
|
|
class FLandscapeToolVisibility : public FLandscapeToolBase<FLandscapeToolStrokeVisibility>
|
|
{
|
|
public:
|
|
FLandscapeToolVisibility(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokeVisibility>(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual bool BeginTool(FEditorViewportClient* ViewportClient, const FLandscapeToolTarget& InTarget, const FVector& InHitLocation, const UViewportInteractor* Interactor = nullptr) override
|
|
{
|
|
ALandscapeProxy* Proxy = InTarget.LandscapeInfo->GetLandscapeProxy();
|
|
UMaterialInterface* HoleMaterial = Proxy->GetLandscapeHoleMaterial();
|
|
if (!HoleMaterial)
|
|
{
|
|
HoleMaterial = Proxy->GetLandscapeMaterial();
|
|
}
|
|
if (!HoleMaterial->GetMaterial()->HasAnyExpressionsInMaterialAndFunctionsOfType<UMaterialExpressionLandscapeVisibilityMask>())
|
|
{
|
|
FMessageDialog::Open(EAppMsgType::Ok,
|
|
LOCTEXT("LandscapeVisibilityMaskMissing", "You must add a \"Landscape Visibility Mask\" node to your material before you can paint visibility."));
|
|
return false;
|
|
}
|
|
|
|
return FLandscapeToolBase<FLandscapeToolStrokeVisibility>::BeginTool(ViewportClient, InTarget, InHitLocation);
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("Visibility"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_Visibility", "Visibility"); };
|
|
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::None | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return false; }
|
|
|
|
virtual ELandscapeToolTargetTypeMask::Type GetSupportedTargetTypes() override
|
|
{
|
|
return ELandscapeToolTargetTypeMask::Visibility;
|
|
}
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolMoveToLevel
|
|
//
|
|
class FLandscapeToolStrokeMoveToLevel : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeMoveToLevel(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
{
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
ALandscape* Landscape = LandscapeInfo ? LandscapeInfo->LandscapeActor.Get() : nullptr;
|
|
|
|
if (Landscape)
|
|
{
|
|
Landscape->Modify();
|
|
LandscapeInfo->Modify();
|
|
|
|
TArray<UObject*> RenameObjects;
|
|
FString MsgBoxList;
|
|
|
|
// Check the Physical Material is same package with Landscape
|
|
if (Landscape->DefaultPhysMaterial && Landscape->DefaultPhysMaterial->GetOutermost() == Landscape->GetOutermost())
|
|
{
|
|
//FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "LandscapePhyMaterial_Warning", "Landscape's DefaultPhysMaterial is in the same package as the Landscape Actor. To support streaming levels, you must move the PhysicalMaterial to another package.") );
|
|
RenameObjects.AddUnique(Landscape->DefaultPhysMaterial);
|
|
MsgBoxList += Landscape->DefaultPhysMaterial->GetPathName();
|
|
MsgBoxList += FString::Printf(TEXT("\n"));
|
|
}
|
|
|
|
// Check the LayerInfoObjects are same package with Landscape
|
|
for (int32 i = 0; i < LandscapeInfo->Layers.Num(); ++i)
|
|
{
|
|
ULandscapeLayerInfoObject* LayerInfo = LandscapeInfo->Layers[i].LayerInfoObj;
|
|
if (LayerInfo && LayerInfo->GetOutermost() == Landscape->GetOutermost())
|
|
{
|
|
RenameObjects.AddUnique(LayerInfo);
|
|
MsgBoxList += LayerInfo->GetPathName();
|
|
MsgBoxList += FString::Printf(TEXT("\n"));
|
|
}
|
|
}
|
|
|
|
auto SelectedComponents = LandscapeInfo->GetSelectedComponents();
|
|
bool bBrush = false;
|
|
if (!SelectedComponents.Num())
|
|
{
|
|
// Get list of verts to update
|
|
// TODO - only retrieve bounds as we don't need the data
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Shrink bounds by 1,1 to avoid GetComponentsInRegion picking up extra components on all sides due to the overlap between components
|
|
LandscapeInfo->GetComponentsInRegion(X1 + 1, Y1 + 1, X2 - 1, Y2 - 1, SelectedComponents);
|
|
bBrush = true;
|
|
}
|
|
|
|
check(ViewportClient->GetScene());
|
|
UWorld* World = ViewportClient->GetScene()->GetWorld();
|
|
check(World);
|
|
if (SelectedComponents.Num())
|
|
{
|
|
bool bIsAllCurrentLevel = true;
|
|
for (ULandscapeComponent* Component : SelectedComponents)
|
|
{
|
|
if (Component->GetLandscapeProxy()->GetLevel() != World->GetCurrentLevel())
|
|
{
|
|
bIsAllCurrentLevel = false;
|
|
}
|
|
}
|
|
|
|
if (bIsAllCurrentLevel)
|
|
{
|
|
// Need to fix double WM
|
|
if (!bBrush)
|
|
{
|
|
// Remove Selection
|
|
LandscapeInfo->ClearSelectedRegion(true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (ULandscapeComponent* Component : SelectedComponents)
|
|
{
|
|
UMaterialInterface* LandscapeMaterial = Component->GetLandscapeMaterial();
|
|
if (LandscapeMaterial && LandscapeMaterial->GetOutermost() == Component->GetOutermost())
|
|
{
|
|
RenameObjects.AddUnique(LandscapeMaterial);
|
|
MsgBoxList += Component->GetName() + TEXT("'s ") + LandscapeMaterial->GetPathName();
|
|
MsgBoxList += FString::Printf(TEXT("\n"));
|
|
//It.RemoveCurrent();
|
|
}
|
|
}
|
|
|
|
if (RenameObjects.Num())
|
|
{
|
|
if (FMessageDialog::Open(EAppMsgType::OkCancel,
|
|
FText::Format(
|
|
NSLOCTEXT("UnrealEd", "LandscapeMoveToStreamingLevel_SharedResources", "The following items must be moved out of the persistent level and into a package that can be shared between multiple levels:\n\n{0}"),
|
|
FText::FromString(MsgBoxList))))
|
|
{
|
|
FString Path = Landscape->GetOutermost()->GetName() + TEXT("_sharedassets/");
|
|
bool bSucceed = ObjectTools::RenameObjects(RenameObjects, false, TEXT(""), Path);
|
|
if (!bSucceed)
|
|
{
|
|
FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "LandscapeMoveToStreamingLevel_RenameFailed", "Move To Streaming Level did not succeed because shared resources could not be moved to a new package."));
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
FScopedSlowTask SlowTask(0, LOCTEXT("BeginMovingLandscapeComponentsToCurrentLevelTask", "Moving Landscape components to current level"));
|
|
SlowTask.MakeDialogDelayed(10); // show slow task dialog after 10 seconds
|
|
|
|
LandscapeInfo->SortSelectedComponents();
|
|
const int32 ComponentSizeVerts = Landscape->NumSubsections * (Landscape->SubsectionSizeQuads + 1);
|
|
const int32 NeedHeightmapSize = 1 << FMath::CeilLogTwo(ComponentSizeVerts);
|
|
|
|
TSet<ALandscapeProxy*> SelectProxies;
|
|
TSet<ULandscapeComponent*> TargetSelectedComponents;
|
|
TArray<ULandscapeHeightfieldCollisionComponent*> TargetSelectedCollisionComponents;
|
|
for (ULandscapeComponent* Component : SelectedComponents)
|
|
{
|
|
SelectProxies.Add(Component->GetLandscapeProxy());
|
|
if (Component->GetLandscapeProxy()->GetOuter() != World->GetCurrentLevel())
|
|
{
|
|
TargetSelectedComponents.Add(Component);
|
|
}
|
|
|
|
ULandscapeHeightfieldCollisionComponent* CollisionComp = Component->CollisionComponent.Get();
|
|
SelectProxies.Add(CollisionComp->GetLandscapeProxy());
|
|
if (CollisionComp->GetLandscapeProxy()->GetOuter() != World->GetCurrentLevel())
|
|
{
|
|
TargetSelectedCollisionComponents.Add(CollisionComp);
|
|
}
|
|
}
|
|
|
|
// Check which ones are need for height map change
|
|
TSet<UTexture2D*> OldHeightmapTextures;
|
|
for (ULandscapeComponent* Component : TargetSelectedComponents)
|
|
{
|
|
Component->Modify();
|
|
OldHeightmapTextures.Add(Component->HeightmapTexture);
|
|
}
|
|
|
|
// Need to split all the component which share Heightmap with selected components
|
|
TMap<ULandscapeComponent*, bool> HeightmapUpdateComponents;
|
|
HeightmapUpdateComponents.Reserve(TargetSelectedComponents.Num() * 4); // worst case
|
|
for (ULandscapeComponent* Component : TargetSelectedComponents)
|
|
{
|
|
// Search neighbor only
|
|
const int32 SearchX = Component->HeightmapTexture->Source.GetSizeX() / NeedHeightmapSize - 1;
|
|
const int32 SearchY = Component->HeightmapTexture->Source.GetSizeY() / NeedHeightmapSize - 1;
|
|
const FIntPoint ComponentBase = Component->GetSectionBase() / Component->ComponentSizeQuads;
|
|
|
|
for (int32 Y = -SearchY; Y <= SearchY; ++Y)
|
|
{
|
|
for (int32 X = -SearchX; X <= SearchX; ++X)
|
|
{
|
|
ULandscapeComponent* const Neighbor = LandscapeInfo->XYtoComponentMap.FindRef(ComponentBase + FIntPoint(X, Y));
|
|
if (Neighbor && Neighbor->HeightmapTexture == Component->HeightmapTexture && !HeightmapUpdateComponents.Contains(Neighbor))
|
|
{
|
|
Neighbor->Modify();
|
|
bool bNeedsMoveToCurrentLevel = TargetSelectedComponents.Contains(Neighbor);
|
|
HeightmapUpdateComponents.Add(Neighbor, bNeedsMoveToCurrentLevel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Changing Heightmap format for selected components
|
|
for (const auto& HeightmapUpdateComponentPair : HeightmapUpdateComponents)
|
|
{
|
|
ALandscape::SplitHeightmap(HeightmapUpdateComponentPair.Key, HeightmapUpdateComponentPair.Value);
|
|
}
|
|
|
|
// Delete if it is no referenced textures...
|
|
for (UTexture2D* Texture : OldHeightmapTextures)
|
|
{
|
|
Texture->SetFlags(RF_Transactional);
|
|
Texture->Modify();
|
|
Texture->MarkPackageDirty();
|
|
Texture->ClearFlags(RF_Standalone);
|
|
}
|
|
|
|
ALandscapeProxy* LandscapeProxy = LandscapeInfo->GetCurrentLevelLandscapeProxy(false);
|
|
if (!LandscapeProxy)
|
|
{
|
|
LandscapeProxy = World->SpawnActor<ALandscapeStreamingProxy>();
|
|
// copy shared properties to this new proxy
|
|
LandscapeProxy->GetSharedProperties(Landscape);
|
|
|
|
// set proxy location
|
|
// by default first component location
|
|
ULandscapeComponent* FirstComponent = *TargetSelectedComponents.CreateConstIterator();
|
|
LandscapeProxy->GetRootComponent()->SetWorldLocationAndRotation(FirstComponent->GetComponentLocation(), FirstComponent->GetComponentRotation());
|
|
LandscapeProxy->LandscapeSectionOffset = FirstComponent->GetSectionBase();
|
|
|
|
// Hide(unregister) the new landscape if owning level currently in hidden state
|
|
if (LandscapeProxy->GetLevel()->bIsVisible == false)
|
|
{
|
|
LandscapeProxy->UnregisterAllComponents();
|
|
}
|
|
}
|
|
|
|
for (ALandscapeProxy* Proxy : SelectProxies)
|
|
{
|
|
Proxy->Modify();
|
|
}
|
|
|
|
LandscapeProxy->Modify();
|
|
LandscapeProxy->MarkPackageDirty();
|
|
|
|
// Handle XY-offset textures (these don't need splitting, as they aren't currently shared between components like heightmaps/weightmaps can be)
|
|
for (ULandscapeComponent* Component : TargetSelectedComponents)
|
|
{
|
|
if (Component->XYOffsetmapTexture)
|
|
{
|
|
Component->XYOffsetmapTexture->Modify();
|
|
Component->XYOffsetmapTexture->Rename(nullptr, LandscapeProxy->GetOutermost());
|
|
}
|
|
}
|
|
|
|
// Change Weight maps...
|
|
{
|
|
FLandscapeEditDataInterface LandscapeEdit(LandscapeInfo);
|
|
for (ULandscapeComponent* Component : TargetSelectedComponents)
|
|
{
|
|
int32 TotalNeededChannels = Component->WeightmapLayerAllocations.Num();
|
|
int32 CurrentLayer = 0;
|
|
TArray<UTexture2D*> NewWeightmapTextures;
|
|
|
|
// Code from ULandscapeComponent::ReallocateWeightmaps
|
|
// Move to other channels left
|
|
while (TotalNeededChannels > 0)
|
|
{
|
|
// UE_LOG(LogLandscape, Log, TEXT("Still need %d channels"), TotalNeededChannels);
|
|
|
|
UTexture2D* CurrentWeightmapTexture = nullptr;
|
|
FLandscapeWeightmapUsage* CurrentWeightmapUsage = nullptr;
|
|
|
|
if (TotalNeededChannels < 4)
|
|
{
|
|
// UE_LOG(LogLandscape, Log, TEXT("Looking for nearest"));
|
|
|
|
// see if we can find a suitable existing weightmap texture with sufficient channels
|
|
int32 BestDistanceSquared = MAX_int32;
|
|
for (auto& WeightmapUsagePair : LandscapeProxy->WeightmapUsageMap)
|
|
{
|
|
FLandscapeWeightmapUsage* TryWeightmapUsage = &WeightmapUsagePair.Value;
|
|
if (TryWeightmapUsage->FreeChannelCount() >= TotalNeededChannels)
|
|
{
|
|
// See if this candidate is closer than any others we've found
|
|
for (int32 ChanIdx = 0; ChanIdx < 4; ChanIdx++)
|
|
{
|
|
if (TryWeightmapUsage->ChannelUsage[ChanIdx] != nullptr)
|
|
{
|
|
int32 TryDistanceSquared = (TryWeightmapUsage->ChannelUsage[ChanIdx]->GetSectionBase() - Component->GetSectionBase()).SizeSquared();
|
|
if (TryDistanceSquared < BestDistanceSquared)
|
|
{
|
|
CurrentWeightmapTexture = WeightmapUsagePair.Key;
|
|
CurrentWeightmapUsage = TryWeightmapUsage;
|
|
BestDistanceSquared = TryDistanceSquared;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool NeedsUpdateResource = false;
|
|
// No suitable weightmap texture
|
|
if (CurrentWeightmapTexture == nullptr)
|
|
{
|
|
Component->MarkPackageDirty();
|
|
|
|
// Weightmap is sized the same as the component
|
|
int32 WeightmapSize = (Component->SubsectionSizeQuads + 1) * Component->NumSubsections;
|
|
|
|
// We need a new weightmap texture
|
|
CurrentWeightmapTexture = LandscapeProxy->CreateLandscapeTexture(WeightmapSize, WeightmapSize, TEXTUREGROUP_Terrain_Weightmap, TSF_BGRA8);
|
|
// Alloc dummy mips
|
|
Component->CreateEmptyTextureMips(CurrentWeightmapTexture);
|
|
CurrentWeightmapTexture->PostEditChange();
|
|
|
|
// Store it in the usage map
|
|
CurrentWeightmapUsage = &LandscapeProxy->WeightmapUsageMap.Add(CurrentWeightmapTexture, FLandscapeWeightmapUsage());
|
|
|
|
// UE_LOG(LogLandscape, Log, TEXT("Making a new texture %s"), *CurrentWeightmapTexture->GetName());
|
|
}
|
|
|
|
NewWeightmapTextures.Add(CurrentWeightmapTexture);
|
|
|
|
for (int32 ChanIdx = 0; ChanIdx < 4 && TotalNeededChannels > 0; ChanIdx++)
|
|
{
|
|
// UE_LOG(LogLandscape, Log, TEXT("Finding allocation for layer %d"), CurrentLayer);
|
|
|
|
if (CurrentWeightmapUsage->ChannelUsage[ChanIdx] == nullptr)
|
|
{
|
|
// Use this allocation
|
|
FWeightmapLayerAllocationInfo& AllocInfo = Component->WeightmapLayerAllocations[CurrentLayer];
|
|
|
|
if (AllocInfo.WeightmapTextureIndex == 255)
|
|
{
|
|
// New layer - zero out the data for this texture channel
|
|
LandscapeEdit.ZeroTextureChannel(CurrentWeightmapTexture, ChanIdx);
|
|
}
|
|
else
|
|
{
|
|
UTexture2D* OldWeightmapTexture = Component->WeightmapTextures[AllocInfo.WeightmapTextureIndex];
|
|
|
|
// Copy the data
|
|
LandscapeEdit.CopyTextureChannel(CurrentWeightmapTexture, ChanIdx, OldWeightmapTexture, AllocInfo.WeightmapTextureChannel);
|
|
LandscapeEdit.ZeroTextureChannel(OldWeightmapTexture, AllocInfo.WeightmapTextureChannel);
|
|
|
|
// Remove the old allocation
|
|
FLandscapeWeightmapUsage* OldWeightmapUsage = Component->GetLandscapeProxy()->WeightmapUsageMap.Find(OldWeightmapTexture);
|
|
OldWeightmapUsage->ChannelUsage[AllocInfo.WeightmapTextureChannel] = nullptr;
|
|
}
|
|
|
|
// Assign the new allocation
|
|
CurrentWeightmapUsage->ChannelUsage[ChanIdx] = Component;
|
|
AllocInfo.WeightmapTextureIndex = NewWeightmapTextures.Num() - 1;
|
|
AllocInfo.WeightmapTextureChannel = ChanIdx;
|
|
CurrentLayer++;
|
|
TotalNeededChannels--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Replace the weightmap textures
|
|
Component->WeightmapTextures = NewWeightmapTextures;
|
|
|
|
// Update the mipmaps for the textures we edited
|
|
for (UTexture2D* WeightmapTexture : Component->WeightmapTextures)
|
|
{
|
|
FLandscapeTextureDataInfo* WeightmapDataInfo = LandscapeEdit.GetTextureDataInfo(WeightmapTexture);
|
|
|
|
int32 NumMips = WeightmapTexture->Source.GetNumMips();
|
|
TArray<FColor*> WeightmapTextureMipData;
|
|
WeightmapTextureMipData.AddUninitialized(NumMips);
|
|
for (int32 MipIdx = 0; MipIdx < NumMips; MipIdx++)
|
|
{
|
|
WeightmapTextureMipData[MipIdx] = (FColor*)WeightmapDataInfo->GetMipData(MipIdx);
|
|
}
|
|
|
|
ULandscapeComponent::UpdateWeightmapMips(Component->NumSubsections, Component->SubsectionSizeQuads, WeightmapTexture, WeightmapTextureMipData, 0, 0, MAX_int32, MAX_int32, WeightmapDataInfo);
|
|
}
|
|
}
|
|
// Need to Repacking all the Weight map (to make it packed well...)
|
|
Landscape->RemoveInvalidWeightmaps();
|
|
}
|
|
|
|
// Move the components to the Proxy actor
|
|
// This does not use the MoveSelectedActorsToCurrentLevel path as there is no support to only move certain components.
|
|
for (ULandscapeComponent* Component :TargetSelectedComponents)
|
|
{
|
|
// Need to move or recreate all related data (Height map, Weight map, maybe collision components, allocation info)
|
|
Component->GetLandscapeProxy()->LandscapeComponents.Remove(Component);
|
|
Component->UnregisterComponent();
|
|
Component->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
|
|
Component->InvalidateLightingCache();
|
|
Component->Rename(nullptr, LandscapeProxy);
|
|
LandscapeProxy->LandscapeComponents.Add(Component);
|
|
Component->AttachToComponent(LandscapeProxy->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform);
|
|
|
|
// clear transient mobile data
|
|
Component->MobileDataSourceHash.Invalidate();
|
|
Component->MobileMaterialInterface = nullptr;
|
|
Component->MobileWeightNormalmapTexture = nullptr;
|
|
|
|
Component->UpdateMaterialInstances();
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("ComponentName"), FText::FromString(Component->GetName()));
|
|
}
|
|
|
|
for (ULandscapeHeightfieldCollisionComponent* Component : TargetSelectedCollisionComponents)
|
|
{
|
|
// Need to move or recreate all related data (Height map, Weight map, maybe collision components, allocation info)
|
|
|
|
Component->GetLandscapeProxy()->CollisionComponents.Remove(Component);
|
|
Component->UnregisterComponent();
|
|
Component->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
|
|
Component->Rename(nullptr, LandscapeProxy);
|
|
LandscapeProxy->CollisionComponents.Add(Component);
|
|
Component->AttachToComponent(LandscapeProxy->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform);
|
|
|
|
// Move any foliage associated
|
|
AInstancedFoliageActor::MoveInstancesForComponentToCurrentLevel(Component);
|
|
|
|
FFormatNamedArguments Args;
|
|
Args.Add(TEXT("ComponentName"), FText::FromString(Component->GetName()));
|
|
}
|
|
|
|
GEditor->SelectNone(false, true);
|
|
GEditor->SelectActor(LandscapeProxy, true, false, true);
|
|
|
|
GEditor->SelectNone(false, true);
|
|
|
|
// Register our new components if destination landscape is registered in scene
|
|
if (LandscapeProxy->GetRootComponent()->IsRegistered())
|
|
{
|
|
LandscapeProxy->RegisterAllComponents();
|
|
}
|
|
|
|
for (ALandscapeProxy* Proxy : SelectProxies)
|
|
{
|
|
if (Proxy->GetRootComponent()->IsRegistered())
|
|
{
|
|
Proxy->RegisterAllComponents();
|
|
}
|
|
}
|
|
|
|
//Landscape->bLockLocation = (LandscapeInfo->XYtoComponentMap.Num() != Landscape->LandscapeComponents.Num());
|
|
|
|
// Remove Selection
|
|
LandscapeInfo->ClearSelectedRegion(true);
|
|
|
|
//EdMode->SetMaskEnable(Landscape->SelectedRegion.Num());
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
class FLandscapeToolMoveToLevel : public FLandscapeToolBase<FLandscapeToolStrokeMoveToLevel>
|
|
{
|
|
public:
|
|
FLandscapeToolMoveToLevel(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokeMoveToLevel>(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("MoveToLevel"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_MoveToLevel", "Move to Streaming Level"); };
|
|
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::SelectComponent | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return false; }
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolAddComponent
|
|
//
|
|
class FLandscapeToolStrokeAddComponent : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeAddComponent(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
, HeightCache(InTarget)
|
|
, XYOffsetCache(InTarget)
|
|
{
|
|
}
|
|
|
|
virtual ~FLandscapeToolStrokeAddComponent()
|
|
{
|
|
// We flush here so here ~FXYOffsetmapAccessor can safely lock the heightmap data to update bounds
|
|
HeightCache.Flush();
|
|
XYOffsetCache.Flush();
|
|
}
|
|
|
|
virtual void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
ALandscapeProxy* Landscape = LandscapeInfo ? LandscapeInfo->GetCurrentLevelLandscapeProxy(true) : nullptr;
|
|
if (Landscape && EdMode->LandscapeRenderAddCollision)
|
|
{
|
|
check(Brush->GetBrushType() == ELandscapeBrushType::Component);
|
|
|
|
// Get list of verts to update
|
|
// TODO - only retrieve bounds as we don't need the data
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Find component range for this block of data, non shared vertices
|
|
int32 ComponentIndexX1, ComponentIndexY1, ComponentIndexX2, ComponentIndexY2;
|
|
ALandscape::CalcComponentIndicesNoOverlap(X1, Y1, X2, Y2, Landscape->ComponentSizeQuads, ComponentIndexX1, ComponentIndexY1, ComponentIndexX2, ComponentIndexY2);
|
|
|
|
// expand the area by one vertex in each direction to ensure normals are calculated correctly
|
|
X1 -= 1;
|
|
Y1 -= 1;
|
|
X2 += 1;
|
|
Y2 += 1;
|
|
|
|
TArray<uint16> Data;
|
|
TArray<FVector> XYOffsetData;
|
|
HeightCache.CacheData(X1, Y1, X2, Y2);
|
|
XYOffsetCache.CacheData(X1, Y1, X2, Y2);
|
|
HeightCache.GetCachedData(X1, Y1, X2, Y2, Data);
|
|
bool bHasXYOffset = XYOffsetCache.GetCachedData(X1, Y1, X2, Y2, XYOffsetData);
|
|
|
|
TArray<ULandscapeComponent*> NewComponents;
|
|
Landscape->Modify();
|
|
LandscapeInfo->Modify();
|
|
for (int32 ComponentIndexY = ComponentIndexY1; ComponentIndexY <= ComponentIndexY2; ComponentIndexY++)
|
|
{
|
|
for (int32 ComponentIndexX = ComponentIndexX1; ComponentIndexX <= ComponentIndexX2; ComponentIndexX++)
|
|
{
|
|
ULandscapeComponent* LandscapeComponent = LandscapeInfo->XYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY));
|
|
if (!LandscapeComponent)
|
|
{
|
|
// Add New component...
|
|
FIntPoint ComponentBase = FIntPoint(ComponentIndexX, ComponentIndexY)*Landscape->ComponentSizeQuads;
|
|
LandscapeComponent = NewObject<ULandscapeComponent>(Landscape, NAME_None, RF_Transactional);
|
|
Landscape->LandscapeComponents.Add(LandscapeComponent);
|
|
NewComponents.Add(LandscapeComponent);
|
|
LandscapeComponent->Init(
|
|
ComponentBase.X, ComponentBase.Y,
|
|
Landscape->ComponentSizeQuads,
|
|
Landscape->NumSubsections,
|
|
Landscape->SubsectionSizeQuads
|
|
);
|
|
LandscapeComponent->AttachToComponent(Landscape->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
|
|
|
|
// Assign shared properties
|
|
LandscapeComponent->bCastStaticShadow = Landscape->bCastStaticShadow;
|
|
LandscapeComponent->bCastShadowAsTwoSided = Landscape->bCastShadowAsTwoSided;
|
|
|
|
int32 ComponentVerts = (Landscape->SubsectionSizeQuads + 1) * Landscape->NumSubsections;
|
|
// Update Weightmap Scale Bias
|
|
LandscapeComponent->WeightmapScaleBias = FVector4(1.0f / (float)ComponentVerts, 1.0f / (float)ComponentVerts, 0.5f / (float)ComponentVerts, 0.5f / (float)ComponentVerts);
|
|
LandscapeComponent->WeightmapSubsectionOffset = (float)(LandscapeComponent->SubsectionSizeQuads + 1) / (float)ComponentVerts;
|
|
|
|
TArray<FColor> HeightData;
|
|
HeightData.Empty(FMath::Square(ComponentVerts));
|
|
HeightData.AddZeroed(FMath::Square(ComponentVerts));
|
|
LandscapeComponent->InitHeightmapData(HeightData, true);
|
|
LandscapeComponent->UpdateMaterialInstances();
|
|
|
|
LandscapeInfo->XYtoComponentMap.Add(FIntPoint(ComponentIndexX, ComponentIndexY), LandscapeComponent);
|
|
LandscapeInfo->XYtoAddCollisionMap.Remove(FIntPoint(ComponentIndexX, ComponentIndexY));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Need to register to use general height/xyoffset data update
|
|
for (int32 Idx = 0; Idx < NewComponents.Num(); Idx++)
|
|
{
|
|
NewComponents[Idx]->RegisterComponent();
|
|
}
|
|
|
|
if (bHasXYOffset)
|
|
{
|
|
XYOffsetCache.SetCachedData(X1, Y1, X2, Y2, XYOffsetData);
|
|
XYOffsetCache.Flush();
|
|
}
|
|
|
|
HeightCache.SetCachedData(X1, Y1, X2, Y2, Data);
|
|
HeightCache.Flush();
|
|
|
|
for (ULandscapeComponent* NewComponent : NewComponents)
|
|
{
|
|
// Update Collision
|
|
NewComponent->UpdateCachedBounds();
|
|
NewComponent->UpdateBounds();
|
|
NewComponent->MarkRenderStateDirty();
|
|
ULandscapeHeightfieldCollisionComponent* CollisionComp = NewComponent->CollisionComponent.Get();
|
|
if (CollisionComp && !bHasXYOffset)
|
|
{
|
|
CollisionComp->MarkRenderStateDirty();
|
|
CollisionComp->RecreateCollision();
|
|
}
|
|
|
|
TMap<ULandscapeLayerInfoObject*, int32> NeighbourLayerInfoObjectCount;
|
|
|
|
// Cover 9 tiles around us to determine which object should we use by default
|
|
for (int32 ComponentIndexX = ComponentIndexX1 - 1; ComponentIndexX <= ComponentIndexX2 + 1; ++ComponentIndexX)
|
|
{
|
|
for (int32 ComponentIndexY = ComponentIndexY1 - 1; ComponentIndexY <= ComponentIndexY2 + 1; ++ComponentIndexY)
|
|
{
|
|
ULandscapeComponent* NeighbourComponent = LandscapeInfo->XYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY));
|
|
|
|
if (NeighbourComponent != nullptr && NeighbourComponent != NewComponent)
|
|
{
|
|
ULandscapeInfo* NeighbourLandscapeInfo = NeighbourComponent->GetLandscapeInfo();
|
|
|
|
for (int32 i = 0; i < NeighbourLandscapeInfo->Layers.Num(); ++i)
|
|
{
|
|
ULandscapeLayerInfoObject* NeighbourLayerInfo = NeighbourLandscapeInfo->Layers[i].LayerInfoObj;
|
|
|
|
if (NeighbourLayerInfo != nullptr)
|
|
{
|
|
TArray<uint8> WeightmapTextureData;
|
|
|
|
FLandscapeComponentDataInterface DataInterface(NeighbourComponent);
|
|
DataInterface.GetWeightmapTextureData(NeighbourLayerInfo, WeightmapTextureData);
|
|
|
|
if (WeightmapTextureData.Num() > 0)
|
|
{
|
|
int32* Count = NeighbourLayerInfoObjectCount.Find(NeighbourLayerInfo);
|
|
|
|
if (Count == nullptr)
|
|
{
|
|
Count = &NeighbourLayerInfoObjectCount.Add(NeighbourLayerInfo, 1);
|
|
}
|
|
|
|
for (uint8 Value : WeightmapTextureData)
|
|
{
|
|
(*Count) += Value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 BestLayerInfoObjectCount = 0;
|
|
ULandscapeLayerInfoObject* BestLayerInfoObject = nullptr;
|
|
|
|
for (auto& LayerInfoObjectCount : NeighbourLayerInfoObjectCount)
|
|
{
|
|
if (LayerInfoObjectCount.Value > BestLayerInfoObjectCount)
|
|
{
|
|
BestLayerInfoObjectCount = LayerInfoObjectCount.Value;
|
|
BestLayerInfoObject = LayerInfoObjectCount.Key;
|
|
}
|
|
}
|
|
|
|
FLandscapeEditDataInterface LandscapeEdit(LandscapeInfo);
|
|
NewComponent->FillLayer(BestLayerInfoObject, LandscapeEdit);
|
|
}
|
|
|
|
EdMode->LandscapeRenderAddCollision = nullptr;
|
|
|
|
// Add/update "add collision" around the newly added components
|
|
{
|
|
// Top row
|
|
int32 ComponentIndexY = ComponentIndexY1 - 1;
|
|
for (int32 ComponentIndexX = ComponentIndexX1 - 1; ComponentIndexX <= ComponentIndexX2 + 1; ++ComponentIndexX)
|
|
{
|
|
if (!LandscapeInfo->XYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY)))
|
|
{
|
|
LandscapeInfo->UpdateAddCollision(FIntPoint(ComponentIndexX, ComponentIndexY));
|
|
}
|
|
}
|
|
|
|
// Sides
|
|
for (ComponentIndexY = ComponentIndexY1; ComponentIndexY <= ComponentIndexY2; ++ComponentIndexY)
|
|
{
|
|
// Left
|
|
int32 ComponentIndexX = ComponentIndexX1 - 1;
|
|
if (!LandscapeInfo->XYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY)))
|
|
{
|
|
LandscapeInfo->UpdateAddCollision(FIntPoint(ComponentIndexX, ComponentIndexY));
|
|
}
|
|
|
|
// Right
|
|
ComponentIndexX = ComponentIndexX1 + 1;
|
|
if (!LandscapeInfo->XYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY)))
|
|
{
|
|
LandscapeInfo->UpdateAddCollision(FIntPoint(ComponentIndexX, ComponentIndexY));
|
|
}
|
|
}
|
|
|
|
// Bottom row
|
|
ComponentIndexY = ComponentIndexY2 + 1;
|
|
for (int32 ComponentIndexX = ComponentIndexX1 - 1; ComponentIndexX <= ComponentIndexX2 + 1; ++ComponentIndexX)
|
|
{
|
|
if (!LandscapeInfo->XYtoComponentMap.FindRef(FIntPoint(ComponentIndexX, ComponentIndexY)))
|
|
{
|
|
LandscapeInfo->UpdateAddCollision(FIntPoint(ComponentIndexX, ComponentIndexY));
|
|
}
|
|
}
|
|
}
|
|
|
|
GEngine->BroadcastOnActorMoved(Landscape);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
FLandscapeHeightCache HeightCache;
|
|
FLandscapeXYOffsetCache<true> XYOffsetCache;
|
|
};
|
|
|
|
class FLandscapeToolAddComponent : public FLandscapeToolBase<FLandscapeToolStrokeAddComponent>
|
|
{
|
|
public:
|
|
FLandscapeToolAddComponent(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokeAddComponent>(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("AddComponent"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_AddComponent", "Add New Landscape Component"); };
|
|
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::None | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return false; }
|
|
|
|
virtual void EnterTool() override
|
|
{
|
|
FLandscapeToolBase<FLandscapeToolStrokeAddComponent>::EnterTool();
|
|
ULandscapeInfo* LandscapeInfo = EdMode->CurrentToolTarget.LandscapeInfo.Get();
|
|
LandscapeInfo->UpdateAllAddCollisions(); // Todo - as this is only used by this tool, move it into this tool?
|
|
}
|
|
|
|
virtual void ExitTool() override
|
|
{
|
|
FLandscapeToolBase<FLandscapeToolStrokeAddComponent>::ExitTool();
|
|
|
|
EdMode->LandscapeRenderAddCollision = nullptr;
|
|
}
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolDeleteComponent
|
|
//
|
|
class FLandscapeToolStrokeDeleteComponent : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeDeleteComponent(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
{
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
if (LandscapeInfo)
|
|
{
|
|
auto SelectedComponents = LandscapeInfo->GetSelectedComponents();
|
|
if (SelectedComponents.Num() == 0)
|
|
{
|
|
// Get list of components to delete from brush
|
|
// TODO - only retrieve bounds as we don't need the vert data
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Shrink bounds by 1,1 to avoid GetComponentsInRegion picking up extra components on all sides due to the overlap between components
|
|
LandscapeInfo->GetComponentsInRegion(X1 + 1, Y1 + 1, X2 - 1, Y2 - 1, SelectedComponents);
|
|
}
|
|
|
|
// Delete the components
|
|
EdMode->DeleteLandscapeComponents(LandscapeInfo, SelectedComponents);
|
|
}
|
|
}
|
|
};
|
|
|
|
class FLandscapeToolDeleteComponent : public FLandscapeToolBase<FLandscapeToolStrokeDeleteComponent>
|
|
{
|
|
public:
|
|
FLandscapeToolDeleteComponent(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokeDeleteComponent>(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("DeleteComponent"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_DeleteComponent", "Delete Landscape Components"); };
|
|
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::SelectComponent | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return false; }
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolCopy
|
|
//
|
|
template<class ToolTarget>
|
|
class FLandscapeToolStrokeCopy : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokeCopy(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
, Cache(InTarget)
|
|
, HeightCache(InTarget)
|
|
, WeightCache(InTarget)
|
|
{
|
|
}
|
|
|
|
struct FGizmoPreData
|
|
{
|
|
float Ratio;
|
|
float Data;
|
|
};
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
//ULandscapeInfo* LandscapeInfo = EdMode->CurrentToolTarget.LandscapeInfo;
|
|
ALandscapeGizmoActiveActor* Gizmo = EdMode->CurrentGizmoActor.Get();
|
|
if (LandscapeInfo && Gizmo && Gizmo->GizmoTexture && Gizmo->GetRootComponent())
|
|
{
|
|
Gizmo->TargetLandscapeInfo = LandscapeInfo;
|
|
|
|
// Get list of verts to update
|
|
// TODO - only retrieve bounds as we don't need the data
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
//Gizmo->Modify(); // No transaction for Copied data as other tools...
|
|
//Gizmo->SelectedData.Empty();
|
|
Gizmo->ClearGizmoData();
|
|
|
|
// Tablet pressure
|
|
//float Pressure = ViewportClient->Viewport->IsPenActive() ? ViewportClient->Viewport->GetTabletPressure() : 1.0f;
|
|
|
|
bool bApplyToAll = EdMode->UISettings->bApplyToAllTargets;
|
|
const int32 LayerNum = LandscapeInfo->Layers.Num();
|
|
|
|
TArray<uint16> HeightData;
|
|
TArray<uint8> WeightDatas; // Weight*Layers...
|
|
TArray<typename ToolTarget::CacheClass::DataType> Data;
|
|
|
|
TSet<ULandscapeLayerInfoObject*> LayerInfoSet;
|
|
|
|
if (bApplyToAll)
|
|
{
|
|
HeightCache.CacheData(X1, Y1, X2, Y2);
|
|
HeightCache.GetCachedData(X1, Y1, X2, Y2, HeightData);
|
|
|
|
WeightCache.CacheData(X1, Y1, X2, Y2);
|
|
WeightCache.GetCachedData(X1, Y1, X2, Y2, WeightDatas, LayerNum);
|
|
}
|
|
else
|
|
{
|
|
Cache.CacheData(X1, Y1, X2, Y2);
|
|
Cache.GetCachedData(X1, Y1, X2, Y2, Data);
|
|
}
|
|
|
|
const float ScaleXY = LandscapeInfo->DrawScale.X;
|
|
float Width = Gizmo->GetWidth();
|
|
float Height = Gizmo->GetHeight();
|
|
|
|
Gizmo->CachedWidth = Width;
|
|
Gizmo->CachedHeight = Height;
|
|
Gizmo->CachedScaleXY = ScaleXY;
|
|
|
|
// Rasterize Gizmo regions
|
|
int32 SizeX = FMath::CeilToInt(Width / ScaleXY);
|
|
int32 SizeY = FMath::CeilToInt(Height / ScaleXY);
|
|
|
|
const float W = (Width - ScaleXY) / (2 * ScaleXY);
|
|
const float H = (Height - ScaleXY) / (2 * ScaleXY);
|
|
|
|
FMatrix WToL = LandscapeInfo->GetLandscapeProxy()->LandscapeActorToWorld().ToMatrixWithScale().InverseFast();
|
|
//FMatrix LToW = Landscape->LocalToWorld();
|
|
|
|
FVector BaseLocation = WToL.TransformPosition(Gizmo->GetActorLocation());
|
|
FMatrix GizmoLocalToLandscape = FRotationTranslationMatrix(FRotator(0, Gizmo->GetActorRotation().Yaw, 0), FVector(BaseLocation.X, BaseLocation.Y, 0));
|
|
|
|
const int32 NeighborNum = 4;
|
|
bool bDidCopy = false;
|
|
bool bFullCopy = !EdMode->UISettings->bUseSelectedRegion || !LandscapeInfo->SelectedRegion.Num();
|
|
//bool bInverted = EdMode->UISettings->bUseSelectedRegion && EdMode->UISettings->bUseNegativeMask;
|
|
|
|
// TODO: This is a mess and badly needs refactoring
|
|
for (int32 Y = 0; Y < SizeY; ++Y)
|
|
{
|
|
for (int32 X = 0; X < SizeX; ++X)
|
|
{
|
|
FVector LandscapeLocal = GizmoLocalToLandscape.TransformPosition(FVector(-W + X, -H + Y, 0));
|
|
int32 LX = FMath::FloorToInt(LandscapeLocal.X);
|
|
int32 LY = FMath::FloorToInt(LandscapeLocal.Y);
|
|
|
|
{
|
|
for (int32 i = -1; (!bApplyToAll && i < 0) || i < LayerNum; ++i)
|
|
{
|
|
// Don't try to copy data for null layers
|
|
if ((bApplyToAll && i >= 0 && !LandscapeInfo->Layers[i].LayerInfoObj) ||
|
|
(!bApplyToAll && !EdMode->CurrentToolTarget.LayerInfo.Get()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
FGizmoPreData GizmoPreData[NeighborNum];
|
|
|
|
for (int32 LocalY = 0; LocalY < 2; ++LocalY)
|
|
{
|
|
for (int32 LocalX = 0; LocalX < 2; ++LocalX)
|
|
{
|
|
int32 x = FMath::Clamp(LX + LocalX, X1, X2);
|
|
int32 y = FMath::Clamp(LY + LocalY, Y1, Y2);
|
|
GizmoPreData[LocalX + LocalY * 2].Ratio = LandscapeInfo->SelectedRegion.FindRef(FIntPoint(x, y));
|
|
int32 index = (x - X1) + (y - Y1)*(1 + X2 - X1);
|
|
|
|
if (bApplyToAll)
|
|
{
|
|
if (i < 0)
|
|
{
|
|
GizmoPreData[LocalX + LocalY * 2].Data = Gizmo->GetNormalizedHeight(HeightData[index]);
|
|
}
|
|
else
|
|
{
|
|
GizmoPreData[LocalX + LocalY * 2].Data = WeightDatas[index*LayerNum + i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
typename ToolTarget::CacheClass::DataType OriginalValue = Data[index];
|
|
if (EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Heightmap)
|
|
{
|
|
GizmoPreData[LocalX + LocalY * 2].Data = Gizmo->GetNormalizedHeight(OriginalValue);
|
|
}
|
|
else
|
|
{
|
|
GizmoPreData[LocalX + LocalY * 2].Data = OriginalValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FGizmoPreData LerpedData;
|
|
float FracX = LandscapeLocal.X - LX;
|
|
float FracY = LandscapeLocal.Y - LY;
|
|
LerpedData.Ratio = bFullCopy ? 1.0f :
|
|
FMath::Lerp(
|
|
FMath::Lerp(GizmoPreData[0].Ratio, GizmoPreData[1].Ratio, FracX),
|
|
FMath::Lerp(GizmoPreData[2].Ratio, GizmoPreData[3].Ratio, FracX),
|
|
FracY
|
|
);
|
|
|
|
LerpedData.Data = FMath::Lerp(
|
|
FMath::Lerp(GizmoPreData[0].Data, GizmoPreData[1].Data, FracX),
|
|
FMath::Lerp(GizmoPreData[2].Data, GizmoPreData[3].Data, FracX),
|
|
FracY
|
|
);
|
|
|
|
if (!bDidCopy && LerpedData.Ratio > 0.0f)
|
|
{
|
|
bDidCopy = true;
|
|
}
|
|
|
|
if (LerpedData.Ratio > 0.0f)
|
|
{
|
|
// Added for LayerNames
|
|
if (bApplyToAll)
|
|
{
|
|
if (i >= 0)
|
|
{
|
|
LayerInfoSet.Add(LandscapeInfo->Layers[i].LayerInfoObj);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Weightmap)
|
|
{
|
|
LayerInfoSet.Add(EdMode->CurrentToolTarget.LayerInfo.Get());
|
|
}
|
|
}
|
|
|
|
FGizmoSelectData* GizmoSelectData = Gizmo->SelectedData.Find(FIntPoint(X, Y));
|
|
if (GizmoSelectData)
|
|
{
|
|
if (bApplyToAll)
|
|
{
|
|
if (i < 0)
|
|
{
|
|
GizmoSelectData->HeightData = LerpedData.Data;
|
|
}
|
|
else
|
|
{
|
|
GizmoSelectData->WeightDataMap.Add(LandscapeInfo->Layers[i].LayerInfoObj, LerpedData.Data);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Heightmap)
|
|
{
|
|
GizmoSelectData->HeightData = LerpedData.Data;
|
|
}
|
|
else
|
|
{
|
|
GizmoSelectData->WeightDataMap.Add(EdMode->CurrentToolTarget.LayerInfo.Get(), LerpedData.Data);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FGizmoSelectData NewData;
|
|
NewData.Ratio = LerpedData.Ratio;
|
|
if (bApplyToAll)
|
|
{
|
|
if (i < 0)
|
|
{
|
|
NewData.HeightData = LerpedData.Data;
|
|
}
|
|
else
|
|
{
|
|
NewData.WeightDataMap.Add(LandscapeInfo->Layers[i].LayerInfoObj, LerpedData.Data);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Heightmap)
|
|
{
|
|
NewData.HeightData = LerpedData.Data;
|
|
}
|
|
else
|
|
{
|
|
NewData.WeightDataMap.Add(EdMode->CurrentToolTarget.LayerInfo.Get(), LerpedData.Data);
|
|
}
|
|
}
|
|
Gizmo->SelectedData.Add(FIntPoint(X, Y), NewData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bDidCopy)
|
|
{
|
|
if (!bApplyToAll)
|
|
{
|
|
if (EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Heightmap)
|
|
{
|
|
Gizmo->DataType = ELandscapeGizmoType(Gizmo->DataType | LGT_Height);
|
|
}
|
|
else
|
|
{
|
|
Gizmo->DataType = ELandscapeGizmoType(Gizmo->DataType | LGT_Weight);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (LayerNum > 0)
|
|
{
|
|
Gizmo->DataType = ELandscapeGizmoType(Gizmo->DataType | LGT_Height);
|
|
Gizmo->DataType = ELandscapeGizmoType(Gizmo->DataType | LGT_Weight);
|
|
}
|
|
else
|
|
{
|
|
Gizmo->DataType = ELandscapeGizmoType(Gizmo->DataType | LGT_Height);
|
|
}
|
|
}
|
|
|
|
Gizmo->SampleData(SizeX, SizeY);
|
|
|
|
// Update LayerInfos
|
|
for (ULandscapeLayerInfoObject* LayerInfo : LayerInfoSet)
|
|
{
|
|
Gizmo->LayerInfos.Add(LayerInfo);
|
|
}
|
|
}
|
|
|
|
//// Clean up Ratio 0 regions... (That was for sampling...)
|
|
//for ( TMap<uint64, FGizmoSelectData>::TIterator It(Gizmo->SelectedData); It; ++It )
|
|
//{
|
|
// FGizmoSelectData& Data = It.Value();
|
|
// if (Data.Ratio <= 0.0f)
|
|
// {
|
|
// Gizmo->SelectedData.Remove(It.Key());
|
|
// }
|
|
//}
|
|
|
|
Gizmo->ExportToClipboard();
|
|
|
|
GEngine->BroadcastLevelActorListChanged();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
typename ToolTarget::CacheClass Cache;
|
|
FLandscapeHeightCache HeightCache;
|
|
FLandscapeFullWeightCache WeightCache;
|
|
};
|
|
|
|
template<class ToolTarget>
|
|
class FLandscapeToolCopy : public FLandscapeToolBase<FLandscapeToolStrokeCopy<ToolTarget>>
|
|
{
|
|
public:
|
|
FLandscapeToolCopy(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokeCopy<ToolTarget> >(InEdMode)
|
|
, BackupCurrentBrush(nullptr)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("Copy"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_Copy", "Copy"); };
|
|
|
|
virtual void SetEditRenderType() override
|
|
{
|
|
GLandscapeEditRenderMode = ELandscapeEditRenderMode::Gizmo | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask);
|
|
GLandscapeEditRenderMode |= (this->EdMode && this->EdMode->CurrentToolTarget.LandscapeInfo.IsValid() && this->EdMode->CurrentToolTarget.LandscapeInfo->SelectedRegion.Num()) ? ELandscapeEditRenderMode::SelectRegion : ELandscapeEditRenderMode::SelectComponent;
|
|
}
|
|
|
|
virtual ELandscapeToolTargetTypeMask::Type GetSupportedTargetTypes() override
|
|
{
|
|
return ELandscapeToolTargetTypeMask::FromType(ToolTarget::TargetType);
|
|
}
|
|
|
|
virtual bool BeginTool(FEditorViewportClient* ViewportClient, const FLandscapeToolTarget& InTarget, const FVector& InHitLocation, const UViewportInteractor* Interactor = nullptr) override
|
|
{
|
|
this->EdMode->GizmoBrush->Tick(ViewportClient, 0.1f);
|
|
|
|
// horrible hack
|
|
// (but avoids duplicating the code from FLandscapeToolBase)
|
|
BackupCurrentBrush = this->EdMode->CurrentBrush;
|
|
this->EdMode->CurrentBrush = this->EdMode->GizmoBrush;
|
|
|
|
return FLandscapeToolBase<FLandscapeToolStrokeCopy<ToolTarget>>::BeginTool(ViewportClient, InTarget, InHitLocation);
|
|
}
|
|
|
|
virtual void EndTool(FEditorViewportClient* ViewportClient) override
|
|
{
|
|
FLandscapeToolBase<FLandscapeToolStrokeCopy<ToolTarget>>::EndTool(ViewportClient);
|
|
|
|
this->EdMode->CurrentBrush = BackupCurrentBrush;
|
|
}
|
|
|
|
protected:
|
|
FLandscapeBrush* BackupCurrentBrush;
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolPaste
|
|
//
|
|
template<class ToolTarget>
|
|
class FLandscapeToolStrokePaste : public FLandscapeToolStrokeBase
|
|
{
|
|
public:
|
|
FLandscapeToolStrokePaste(FEdModeLandscape* InEdMode, FEditorViewportClient* InViewportClient, const FLandscapeToolTarget& InTarget)
|
|
: FLandscapeToolStrokeBase(InEdMode, InViewportClient, InTarget)
|
|
, Cache(InTarget)
|
|
, HeightCache(InTarget)
|
|
, WeightCache(InTarget)
|
|
{
|
|
}
|
|
|
|
void Apply(FEditorViewportClient* ViewportClient, FLandscapeBrush* Brush, const ULandscapeEditorObject* UISettings, const TArray<FLandscapeToolInteractorPosition>& InteractorPositions)
|
|
{
|
|
//ULandscapeInfo* LandscapeInfo = EdMode->CurrentToolTarget.LandscapeInfo;
|
|
ALandscapeGizmoActiveActor* Gizmo = EdMode->CurrentGizmoActor.Get();
|
|
// Cache and copy in Gizmo's region...
|
|
if (LandscapeInfo && Gizmo && Gizmo->GetRootComponent())
|
|
{
|
|
if (Gizmo->SelectedData.Num() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Automatically fill in any placeholder layers
|
|
// This gives a much better user experience when copying data to a newly created landscape
|
|
for (ULandscapeLayerInfoObject* LayerInfo : Gizmo->LayerInfos)
|
|
{
|
|
int32 LayerInfoIndex = LandscapeInfo->GetLayerInfoIndex(LayerInfo);
|
|
if (LayerInfoIndex == INDEX_NONE)
|
|
{
|
|
LayerInfoIndex = LandscapeInfo->GetLayerInfoIndex(LayerInfo->LayerName);
|
|
if (LayerInfoIndex != INDEX_NONE)
|
|
{
|
|
FLandscapeInfoLayerSettings& LayerSettings = LandscapeInfo->Layers[LayerInfoIndex];
|
|
|
|
if (LayerSettings.LayerInfoObj == nullptr)
|
|
{
|
|
LayerSettings.Owner = LandscapeInfo->GetLandscapeProxy(); // this isn't strictly accurate, but close enough
|
|
LayerSettings.LayerInfoObj = LayerInfo;
|
|
LayerSettings.bValid = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Gizmo->TargetLandscapeInfo = LandscapeInfo;
|
|
float ScaleXY = LandscapeInfo->DrawScale.X;
|
|
|
|
//LandscapeInfo->Modify();
|
|
|
|
// Get list of verts to update
|
|
FLandscapeBrushData BrushInfo = Brush->ApplyBrush(InteractorPositions);
|
|
if (!BrushInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int32 X1, Y1, X2, Y2;
|
|
BrushInfo.GetInclusiveBounds(X1, Y1, X2, Y2);
|
|
|
|
// Tablet pressure
|
|
float Pressure = (ViewportClient && ViewportClient->Viewport->IsPenActive()) ? ViewportClient->Viewport->GetTabletPressure() : 1.0f;
|
|
|
|
// expand the area by one vertex in each direction to ensure normals are calculated correctly
|
|
X1 -= 1;
|
|
Y1 -= 1;
|
|
X2 += 1;
|
|
Y2 += 1;
|
|
|
|
const bool bApplyToAll = EdMode->UISettings->bApplyToAllTargets;
|
|
const int32 LayerNum = Gizmo->LayerInfos.Num() > 0 ? LandscapeInfo->Layers.Num() : 0;
|
|
|
|
TArray<uint16> HeightData;
|
|
TArray<uint8> WeightDatas; // Weight*Layers...
|
|
TArray<typename ToolTarget::CacheClass::DataType> Data;
|
|
|
|
if (bApplyToAll)
|
|
{
|
|
HeightCache.CacheData(X1, Y1, X2, Y2);
|
|
HeightCache.GetCachedData(X1, Y1, X2, Y2, HeightData);
|
|
|
|
if (LayerNum > 0)
|
|
{
|
|
WeightCache.CacheData(X1, Y1, X2, Y2);
|
|
WeightCache.GetCachedData(X1, Y1, X2, Y2, WeightDatas, LayerNum);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Cache.CacheData(X1, Y1, X2, Y2);
|
|
Cache.GetCachedData(X1, Y1, X2, Y2, Data);
|
|
}
|
|
|
|
const float Width = Gizmo->GetWidth();
|
|
const float Height = Gizmo->GetHeight();
|
|
|
|
const float W = Gizmo->GetWidth() / (2 * ScaleXY);
|
|
const float H = Gizmo->GetHeight() / (2 * ScaleXY);
|
|
|
|
const float SignX = Gizmo->GetRootComponent()->RelativeScale3D.X > 0.0f ? 1.0f : -1.0f;
|
|
const float SignY = Gizmo->GetRootComponent()->RelativeScale3D.Y > 0.0f ? 1.0f : -1.0f;
|
|
|
|
const float ScaleX = Gizmo->CachedWidth / Width * ScaleXY / Gizmo->CachedScaleXY;
|
|
const float ScaleY = Gizmo->CachedHeight / Height * ScaleXY / Gizmo->CachedScaleXY;
|
|
|
|
FMatrix WToL = LandscapeInfo->GetLandscapeProxy()->LandscapeActorToWorld().ToMatrixWithScale().InverseFast();
|
|
//FMatrix LToW = Landscape->LocalToWorld();
|
|
FVector BaseLocation = WToL.TransformPosition(Gizmo->GetActorLocation());
|
|
//FMatrix LandscapeLocalToGizmo = FRotationTranslationMatrix(FRotator(0, Gizmo->Rotation.Yaw, 0), FVector(BaseLocation.X - W + 0.5, BaseLocation.Y - H + 0.5, 0));
|
|
FMatrix LandscapeToGizmoLocal =
|
|
(FTranslationMatrix(FVector((-W + 0.5)*SignX, (-H + 0.5)*SignY, 0)) * FScaleRotationTranslationMatrix(FVector(SignX, SignY, 1.0f), FRotator(0, Gizmo->GetActorRotation().Yaw, 0), FVector(BaseLocation.X, BaseLocation.Y, 0))).InverseFast();
|
|
|
|
for (int32 Y = BrushInfo.GetBounds().Min.Y; Y < BrushInfo.GetBounds().Max.Y; Y++)
|
|
{
|
|
const float* BrushScanline = BrushInfo.GetDataPtr(FIntPoint(0, Y));
|
|
|
|
for (int32 X = BrushInfo.GetBounds().Min.X; X < BrushInfo.GetBounds().Max.X; X++)
|
|
{
|
|
const float BrushValue = BrushScanline[X];
|
|
|
|
if (BrushValue > 0.0f)
|
|
{
|
|
// TODO: This is a mess and badly needs refactoring
|
|
|
|
// Value before we apply our painting
|
|
int32 index = (X - X1) + (Y - Y1)*(1 + X2 - X1);
|
|
float PaintAmount = (Brush->GetBrushType() == ELandscapeBrushType::Gizmo) ? BrushValue : BrushValue * EdMode->UISettings->ToolStrength * Pressure;
|
|
|
|
FVector GizmoLocal = LandscapeToGizmoLocal.TransformPosition(FVector(X, Y, 0));
|
|
GizmoLocal.X *= ScaleX * SignX;
|
|
GizmoLocal.Y *= ScaleY * SignY;
|
|
|
|
int32 LX = FMath::FloorToInt(GizmoLocal.X);
|
|
int32 LY = FMath::FloorToInt(GizmoLocal.Y);
|
|
|
|
float FracX = GizmoLocal.X - LX;
|
|
float FracY = GizmoLocal.Y - LY;
|
|
|
|
FGizmoSelectData* Data00 = Gizmo->SelectedData.Find(FIntPoint(LX, LY));
|
|
FGizmoSelectData* Data10 = Gizmo->SelectedData.Find(FIntPoint(LX + 1, LY));
|
|
FGizmoSelectData* Data01 = Gizmo->SelectedData.Find(FIntPoint(LX, LY + 1));
|
|
FGizmoSelectData* Data11 = Gizmo->SelectedData.Find(FIntPoint(LX + 1, LY + 1));
|
|
|
|
for (int32 i = -1; (!bApplyToAll && i < 0) || i < LayerNum; ++i)
|
|
{
|
|
if ((bApplyToAll && (i < 0)) || (!bApplyToAll && EdMode->CurrentToolTarget.TargetType == ELandscapeToolTargetType::Heightmap))
|
|
{
|
|
float OriginalValue;
|
|
if (bApplyToAll)
|
|
{
|
|
OriginalValue = HeightData[index];
|
|
}
|
|
else
|
|
{
|
|
OriginalValue = Data[index];
|
|
}
|
|
|
|
float Value = LandscapeDataAccess::GetLocalHeight(OriginalValue);
|
|
|
|
float DestValue = FLandscapeHeightCache::ClampValue(
|
|
LandscapeDataAccess::GetTexHeight(
|
|
FMath::Lerp(
|
|
FMath::Lerp(Data00 ? FMath::Lerp(Value, Gizmo->GetLandscapeHeight(Data00->HeightData), Data00->Ratio) : Value,
|
|
Data10 ? FMath::Lerp(Value, Gizmo->GetLandscapeHeight(Data10->HeightData), Data10->Ratio) : Value, FracX),
|
|
FMath::Lerp(Data01 ? FMath::Lerp(Value, Gizmo->GetLandscapeHeight(Data01->HeightData), Data01->Ratio) : Value,
|
|
Data11 ? FMath::Lerp(Value, Gizmo->GetLandscapeHeight(Data11->HeightData), Data11->Ratio) : Value, FracX),
|
|
FracY
|
|
))
|
|
);
|
|
|
|
switch (EdMode->UISettings->PasteMode)
|
|
{
|
|
case ELandscapeToolNoiseMode::Add:
|
|
PaintAmount = OriginalValue < DestValue ? PaintAmount : 0.0f;
|
|
break;
|
|
case ELandscapeToolNoiseMode::Sub:
|
|
PaintAmount = OriginalValue > DestValue ? PaintAmount : 0.0f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (bApplyToAll)
|
|
{
|
|
HeightData[index] = FMath::Lerp(OriginalValue, DestValue, PaintAmount);
|
|
}
|
|
else
|
|
{
|
|
Data[index] = FMath::Lerp(OriginalValue, DestValue, PaintAmount);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ULandscapeLayerInfoObject* LayerInfo;
|
|
float OriginalValue;
|
|
if (bApplyToAll)
|
|
{
|
|
LayerInfo = LandscapeInfo->Layers[i].LayerInfoObj;
|
|
OriginalValue = WeightDatas[index*LayerNum + i];
|
|
}
|
|
else
|
|
{
|
|
LayerInfo = EdMode->CurrentToolTarget.LayerInfo.Get();
|
|
OriginalValue = Data[index];
|
|
}
|
|
|
|
float DestValue = FLandscapeAlphaCache::ClampValue(
|
|
FMath::Lerp(
|
|
FMath::Lerp(Data00 ? FMath::Lerp(OriginalValue, Data00->WeightDataMap.FindRef(LayerInfo), Data00->Ratio) : OriginalValue,
|
|
Data10 ? FMath::Lerp(OriginalValue, Data10->WeightDataMap.FindRef(LayerInfo), Data10->Ratio) : OriginalValue, FracX),
|
|
FMath::Lerp(Data01 ? FMath::Lerp(OriginalValue, Data01->WeightDataMap.FindRef(LayerInfo), Data01->Ratio) : OriginalValue,
|
|
Data11 ? FMath::Lerp(OriginalValue, Data11->WeightDataMap.FindRef(LayerInfo), Data11->Ratio) : OriginalValue, FracX),
|
|
FracY
|
|
));
|
|
|
|
if (bApplyToAll)
|
|
{
|
|
WeightDatas[index*LayerNum + i] = FMath::Lerp(OriginalValue, DestValue, PaintAmount);
|
|
}
|
|
else
|
|
{
|
|
Data[index] = FMath::Lerp(OriginalValue, DestValue, PaintAmount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (ULandscapeLayerInfoObject* LayerInfo : Gizmo->LayerInfos)
|
|
{
|
|
if (LandscapeInfo->GetLayerInfoIndex(LayerInfo) != INDEX_NONE)
|
|
{
|
|
WeightCache.AddDirtyLayer(LayerInfo);
|
|
}
|
|
}
|
|
|
|
if (bApplyToAll)
|
|
{
|
|
HeightCache.SetCachedData(X1, Y1, X2, Y2, HeightData);
|
|
HeightCache.Flush();
|
|
if (WeightDatas.Num())
|
|
{
|
|
// Set the layer data, bypassing painting restrictions because it doesn't work well when altering multiple layers
|
|
WeightCache.SetCachedData(X1, Y1, X2, Y2, WeightDatas, LayerNum, ELandscapeLayerPaintingRestriction::None);
|
|
}
|
|
WeightCache.Flush();
|
|
}
|
|
else
|
|
{
|
|
Cache.SetCachedData(X1, Y1, X2, Y2, Data);
|
|
Cache.Flush();
|
|
}
|
|
|
|
GEngine->BroadcastLevelActorListChanged();
|
|
}
|
|
}
|
|
|
|
protected:
|
|
typename ToolTarget::CacheClass Cache;
|
|
FLandscapeHeightCache HeightCache;
|
|
FLandscapeFullWeightCache WeightCache;
|
|
};
|
|
|
|
template<class ToolTarget>
|
|
class FLandscapeToolPaste : public FLandscapeToolBase<FLandscapeToolStrokePaste<ToolTarget>>
|
|
{
|
|
public:
|
|
FLandscapeToolPaste(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolBase<FLandscapeToolStrokePaste<ToolTarget>>(InEdMode)
|
|
, bUseGizmoRegion(false)
|
|
, BackupCurrentBrush(nullptr)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("Paste"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_Region", "Region Copy/Paste"); };
|
|
|
|
virtual void SetEditRenderType() override
|
|
{
|
|
GLandscapeEditRenderMode = ELandscapeEditRenderMode::Gizmo | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask);
|
|
GLandscapeEditRenderMode |= (this->EdMode && this->EdMode->CurrentToolTarget.LandscapeInfo.IsValid() && this->EdMode->CurrentToolTarget.LandscapeInfo->SelectedRegion.Num()) ? ELandscapeEditRenderMode::SelectRegion : ELandscapeEditRenderMode::SelectComponent;
|
|
}
|
|
|
|
void SetGizmoMode(bool InbUseGizmoRegion)
|
|
{
|
|
bUseGizmoRegion = InbUseGizmoRegion;
|
|
}
|
|
|
|
virtual ELandscapeToolTargetTypeMask::Type GetSupportedTargetTypes() override
|
|
{
|
|
return ELandscapeToolTargetTypeMask::FromType(ToolTarget::TargetType);
|
|
}
|
|
|
|
virtual bool BeginTool(FEditorViewportClient* ViewportClient, const FLandscapeToolTarget& InTarget, const FVector& InHitLocation, const UViewportInteractor* Interactor = nullptr) override
|
|
{
|
|
this->EdMode->GizmoBrush->Tick(ViewportClient, 0.1f);
|
|
|
|
// horrible hack
|
|
// (but avoids duplicating the code from FLandscapeToolBase)
|
|
BackupCurrentBrush = this->EdMode->CurrentBrush;
|
|
if (bUseGizmoRegion)
|
|
{
|
|
this->EdMode->CurrentBrush = this->EdMode->GizmoBrush;
|
|
}
|
|
|
|
return FLandscapeToolBase<FLandscapeToolStrokePaste<ToolTarget>>::BeginTool(ViewportClient, InTarget, InHitLocation);
|
|
}
|
|
|
|
virtual void EndTool(FEditorViewportClient* ViewportClient) override
|
|
{
|
|
FLandscapeToolBase<FLandscapeToolStrokePaste<ToolTarget>>::EndTool(ViewportClient);
|
|
|
|
if (bUseGizmoRegion)
|
|
{
|
|
this->EdMode->CurrentBrush = BackupCurrentBrush;
|
|
}
|
|
check(this->EdMode->CurrentBrush == BackupCurrentBrush);
|
|
}
|
|
|
|
virtual bool MouseMove(FEditorViewportClient* ViewportClient, FViewport* Viewport, int32 x, int32 y) override
|
|
{
|
|
if (bUseGizmoRegion)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return FLandscapeToolBase<FLandscapeToolStrokePaste<ToolTarget>>::MouseMove(ViewportClient, Viewport, x, y);
|
|
}
|
|
|
|
protected:
|
|
bool bUseGizmoRegion;
|
|
FLandscapeBrush* BackupCurrentBrush;
|
|
};
|
|
|
|
//
|
|
// FLandscapeToolCopyPaste
|
|
//
|
|
template<class ToolTarget>
|
|
class FLandscapeToolCopyPaste : public FLandscapeToolPaste<ToolTarget>
|
|
{
|
|
public:
|
|
FLandscapeToolCopyPaste(FEdModeLandscape* InEdMode)
|
|
: FLandscapeToolPaste<ToolTarget>(InEdMode)
|
|
, CopyTool(InEdMode)
|
|
{
|
|
}
|
|
|
|
// Just hybrid of Copy and Paste tool
|
|
virtual const TCHAR* GetToolName() override { return TEXT("CopyPaste"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_Region", "Region Copy/Paste"); };
|
|
|
|
virtual void EnterTool() override
|
|
{
|
|
// Make sure gizmo actor is selected
|
|
ALandscapeGizmoActiveActor* Gizmo = this->EdMode->CurrentGizmoActor.Get();
|
|
if (Gizmo)
|
|
{
|
|
GEditor->SelectNone(false, true);
|
|
GEditor->SelectActor(Gizmo, true, false, true);
|
|
}
|
|
}
|
|
|
|
// Copy tool doesn't use any view information, so just do it as one function
|
|
void Copy()
|
|
{
|
|
CopyTool.BeginTool(nullptr, this->EdMode->CurrentToolTarget, FVector::ZeroVector);
|
|
CopyTool.EndTool(nullptr);
|
|
}
|
|
|
|
void Paste()
|
|
{
|
|
this->SetGizmoMode(true);
|
|
this->BeginTool(nullptr, this->EdMode->CurrentToolTarget, FVector::ZeroVector);
|
|
this->EndTool(nullptr);
|
|
this->SetGizmoMode(false);
|
|
}
|
|
|
|
protected:
|
|
FLandscapeToolCopy<ToolTarget> CopyTool;
|
|
};
|
|
|
|
void FEdModeLandscape::CopyDataToGizmo()
|
|
{
|
|
// For Copy operation...
|
|
if (CopyPasteTool /*&& CopyPasteTool == CurrentTool*/)
|
|
{
|
|
CopyPasteTool->Copy();
|
|
}
|
|
if (CurrentGizmoActor.IsValid())
|
|
{
|
|
GEditor->SelectNone(false, true);
|
|
GEditor->SelectActor(CurrentGizmoActor.Get(), true, true, true);
|
|
}
|
|
}
|
|
|
|
void FEdModeLandscape::PasteDataFromGizmo()
|
|
{
|
|
// For Paste for Gizmo Region operation...
|
|
if (CopyPasteTool /*&& CopyPasteTool == CurrentTool*/)
|
|
{
|
|
CopyPasteTool->Paste();
|
|
}
|
|
if (CurrentGizmoActor.IsValid())
|
|
{
|
|
GEditor->SelectNone(false, true);
|
|
GEditor->SelectActor(CurrentGizmoActor.Get(), true, true, true);
|
|
}
|
|
}
|
|
|
|
//
|
|
// FLandscapeToolNewLandscape
|
|
//
|
|
class FLandscapeToolNewLandscape : public FLandscapeTool
|
|
{
|
|
public:
|
|
FEdModeLandscape* EdMode;
|
|
ENewLandscapePreviewMode::Type NewLandscapePreviewMode;
|
|
|
|
FLandscapeToolNewLandscape(FEdModeLandscape* InEdMode)
|
|
: FLandscapeTool()
|
|
, EdMode(InEdMode)
|
|
, NewLandscapePreviewMode(ENewLandscapePreviewMode::NewLandscape)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("NewLandscape"); }
|
|
virtual FText GetDisplayName() override { return NSLOCTEXT("UnrealEd", "LandscapeMode_NewLandscape", "New Landscape"); };
|
|
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::None | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return false; }
|
|
|
|
virtual void EnterTool() override
|
|
{
|
|
EdMode->NewLandscapePreviewMode = NewLandscapePreviewMode;
|
|
EdMode->UISettings->ImportLandscapeData();
|
|
}
|
|
|
|
virtual void ExitTool() override
|
|
{
|
|
NewLandscapePreviewMode = EdMode->NewLandscapePreviewMode;
|
|
EdMode->NewLandscapePreviewMode = ENewLandscapePreviewMode::None;
|
|
EdMode->UISettings->ClearImportLandscapeData();
|
|
}
|
|
|
|
virtual bool BeginTool(FEditorViewportClient* ViewportClient, const FLandscapeToolTarget& Target, const FVector& InHitLocation, const UViewportInteractor* Interactor = nullptr) override
|
|
{
|
|
// does nothing
|
|
return false;
|
|
}
|
|
|
|
virtual void EndTool(FEditorViewportClient* ViewportClient) override
|
|
{
|
|
// does nothing
|
|
}
|
|
|
|
virtual bool MouseMove(FEditorViewportClient* ViewportClient, FViewport* Viewport, int32 x, int32 y) override
|
|
{
|
|
// does nothing
|
|
return false;
|
|
}
|
|
};
|
|
|
|
|
|
//
|
|
// FLandscapeToolResizeLandscape
|
|
//
|
|
class FLandscapeToolResizeLandscape : public FLandscapeTool
|
|
{
|
|
public:
|
|
FEdModeLandscape* EdMode;
|
|
|
|
FLandscapeToolResizeLandscape(FEdModeLandscape* InEdMode)
|
|
: FLandscapeTool()
|
|
, EdMode(InEdMode)
|
|
{
|
|
}
|
|
|
|
virtual const TCHAR* GetToolName() override { return TEXT("ResizeLandscape"); }
|
|
virtual FText GetDisplayName() override { return LOCTEXT("LandscapeMode_ResizeLandscape", "Change Landscape Component Size"); };
|
|
|
|
virtual void SetEditRenderType() override { GLandscapeEditRenderMode = ELandscapeEditRenderMode::None | (GLandscapeEditRenderMode & ELandscapeEditRenderMode::BitMaskForMask); }
|
|
virtual bool SupportsMask() override { return false; }
|
|
|
|
virtual void EnterTool() override
|
|
{
|
|
const int32 ComponentSizeQuads = EdMode->CurrentToolTarget.LandscapeInfo->ComponentSizeQuads;
|
|
int32 MinX, MinY, MaxX, MaxY;
|
|
if (EdMode->CurrentToolTarget.LandscapeInfo->GetLandscapeExtent(MinX, MinY, MaxX, MaxY))
|
|
{
|
|
EdMode->UISettings->ResizeLandscape_Original_ComponentCount.X = (MaxX - MinX) / ComponentSizeQuads;
|
|
EdMode->UISettings->ResizeLandscape_Original_ComponentCount.Y = (MaxY - MinY) / ComponentSizeQuads;
|
|
EdMode->UISettings->ResizeLandscape_ComponentCount = EdMode->UISettings->ResizeLandscape_Original_ComponentCount;
|
|
}
|
|
else
|
|
{
|
|
EdMode->UISettings->ResizeLandscape_Original_ComponentCount = FIntPoint::ZeroValue;
|
|
EdMode->UISettings->ResizeLandscape_ComponentCount = FIntPoint::ZeroValue;
|
|
}
|
|
EdMode->UISettings->ResizeLandscape_Original_QuadsPerSection = EdMode->CurrentToolTarget.LandscapeInfo->SubsectionSizeQuads;
|
|
EdMode->UISettings->ResizeLandscape_Original_SectionsPerComponent = EdMode->CurrentToolTarget.LandscapeInfo->ComponentNumSubsections;
|
|
EdMode->UISettings->ResizeLandscape_QuadsPerSection = EdMode->UISettings->ResizeLandscape_Original_QuadsPerSection;
|
|
EdMode->UISettings->ResizeLandscape_SectionsPerComponent = EdMode->UISettings->ResizeLandscape_Original_SectionsPerComponent;
|
|
}
|
|
|
|
virtual void ExitTool() override
|
|
{
|
|
}
|
|
|
|
virtual bool BeginTool(FEditorViewportClient* ViewportClient, const FLandscapeToolTarget& Target, const FVector& InHitLocation, const UViewportInteractor* Interactor = nullptr) override
|
|
{
|
|
// does nothing
|
|
return false;
|
|
}
|
|
|
|
virtual void EndTool(FEditorViewportClient* ViewportClient) override
|
|
{
|
|
// does nothing
|
|
}
|
|
|
|
virtual bool MouseMove(FEditorViewportClient* ViewportClient, FViewport* Viewport, int32 x, int32 y) override
|
|
{
|
|
// does nothing
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void FEdModeLandscape::InitializeTool_NewLandscape()
|
|
{
|
|
auto Tool_NewLandscape = MakeUnique<FLandscapeToolNewLandscape>(this);
|
|
Tool_NewLandscape->ValidBrushes.Add("BrushSet_Dummy");
|
|
LandscapeTools.Add(MoveTemp(Tool_NewLandscape));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_ResizeLandscape()
|
|
{
|
|
auto Tool_ResizeLandscape = MakeUnique<FLandscapeToolResizeLandscape>(this);
|
|
Tool_ResizeLandscape->ValidBrushes.Add("BrushSet_Dummy");
|
|
LandscapeTools.Add(MoveTemp(Tool_ResizeLandscape));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_Select()
|
|
{
|
|
auto Tool_Select = MakeUnique<FLandscapeToolSelect>(this);
|
|
Tool_Select->ValidBrushes.Add("BrushSet_Component");
|
|
LandscapeTools.Add(MoveTemp(Tool_Select));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_AddComponent()
|
|
{
|
|
auto Tool_AddComponent = MakeUnique<FLandscapeToolAddComponent>(this);
|
|
Tool_AddComponent->ValidBrushes.Add("BrushSet_Component");
|
|
LandscapeTools.Add(MoveTemp(Tool_AddComponent));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_DeleteComponent()
|
|
{
|
|
auto Tool_DeleteComponent = MakeUnique<FLandscapeToolDeleteComponent>(this);
|
|
Tool_DeleteComponent->ValidBrushes.Add("BrushSet_Component");
|
|
LandscapeTools.Add(MoveTemp(Tool_DeleteComponent));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_MoveToLevel()
|
|
{
|
|
auto Tool_MoveToLevel = MakeUnique<FLandscapeToolMoveToLevel>(this);
|
|
Tool_MoveToLevel->ValidBrushes.Add("BrushSet_Component");
|
|
LandscapeTools.Add(MoveTemp(Tool_MoveToLevel));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_Mask()
|
|
{
|
|
auto Tool_Mask = MakeUnique<FLandscapeToolMask>(this);
|
|
Tool_Mask->ValidBrushes.Add("BrushSet_Circle");
|
|
Tool_Mask->ValidBrushes.Add("BrushSet_Alpha");
|
|
Tool_Mask->ValidBrushes.Add("BrushSet_Pattern");
|
|
LandscapeTools.Add(MoveTemp(Tool_Mask));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_CopyPaste()
|
|
{
|
|
auto Tool_CopyPaste_Heightmap = MakeUnique<FLandscapeToolCopyPaste<FHeightmapToolTarget>>(this);
|
|
Tool_CopyPaste_Heightmap->ValidBrushes.Add("BrushSet_Circle");
|
|
Tool_CopyPaste_Heightmap->ValidBrushes.Add("BrushSet_Alpha");
|
|
Tool_CopyPaste_Heightmap->ValidBrushes.Add("BrushSet_Pattern");
|
|
Tool_CopyPaste_Heightmap->ValidBrushes.Add("BrushSet_Gizmo");
|
|
CopyPasteTool = Tool_CopyPaste_Heightmap.Get();
|
|
LandscapeTools.Add(MoveTemp(Tool_CopyPaste_Heightmap));
|
|
|
|
//auto Tool_CopyPaste_Weightmap = MakeUnique<FLandscapeToolCopyPaste<FWeightmapToolTarget>>(this);
|
|
//Tool_CopyPaste_Weightmap->ValidBrushes.Add("BrushSet_Circle");
|
|
//Tool_CopyPaste_Weightmap->ValidBrushes.Add("BrushSet_Alpha");
|
|
//Tool_CopyPaste_Weightmap->ValidBrushes.Add("BrushSet_Pattern");
|
|
//Tool_CopyPaste_Weightmap->ValidBrushes.Add("BrushSet_Gizmo");
|
|
//LandscapeTools.Add(MoveTemp(Tool_CopyPaste_Weightmap));
|
|
}
|
|
|
|
void FEdModeLandscape::InitializeTool_Visibility()
|
|
{
|
|
auto Tool_Visibility = MakeUnique<FLandscapeToolVisibility>(this);
|
|
Tool_Visibility->ValidBrushes.Add("BrushSet_Circle");
|
|
Tool_Visibility->ValidBrushes.Add("BrushSet_Alpha");
|
|
Tool_Visibility->ValidBrushes.Add("BrushSet_Pattern");
|
|
LandscapeTools.Add(MoveTemp(Tool_Visibility));
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|